home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 037a / exec33.zip / SPAWN.ASM < prev    next >
Assembly Source File  |  1991-11-26  |  89KB  |  3,536 lines

  1. ;
  2. ;    --- Version 3.3 91-11-26 15:42 ---
  3. ;
  4. ;    SPAWN.ASM - Main function for memory swapping spawn call.
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic GmbH
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ;>e
  14. ; Assemble with
  15. ;
  16. ; tasm  /DPASCAL spawn,spawnp          - Turbo Pascal (Tasm only), near
  17. ; tasm  /DPASCAL /DFARCALL spawn,spawnp    - Turbo Pascal (Tasm only), far
  18. ; ?asm  spawn;                  - C, default model (small)
  19. ; ?asm  /DMODL=large spawn          - C, large model
  20. ;
  21. ;    NOTE:    For C, change the 'model' directive below according to your
  22. ;        memory model, or define MODL=xxx on the command line.
  23. ;
  24. ;        For Turbo C Huge model, you must give /DTC_HUGE on the
  25. ;        command line, or define it here.
  26. ;
  27. ;
  28. ; Main function:
  29. ;
  30. ;   PASCAL:
  31. ;       function do_spawn (swapping: integer; 
  32. ;                  execfname: string;
  33. ;               cmdtail: string; 
  34. ;                  envlen: word; 
  35. ;               var envp;
  36. ;               stdin: string; 
  37. ;                   stdout: string;
  38. ;               stderr: string): integer;    
  39. ;
  40. ;   C:
  41. ;       int do_spawn (int swapping,
  42. ;              char *execfname, 
  43. ;              char *cmdtail,
  44. ;              unsigned envlen, 
  45. ;              char *envp,
  46. ;              char *stdin,
  47. ;              char *stdout,
  48. ;              char *stderr)
  49. ;
  50. ;   Parameters:
  51. ;
  52. ;    swapping - swap/spawn/exec function:
  53. ;            < 0: Exec, don't swap
  54. ;                0: Spawn, don't swap
  55. ;            > 0: Spawn, swap
  56. ;                 in this case, prep_swap must have 
  57. ;                 been called beforehand (see below).
  58. ;
  59. ;    cmdtail - command tail for EXEC.
  60. ;
  61. ;    execfname - name and path of file to execute.
  62. ;
  63. ;    envlen - length of environment copy (may be 0).
  64. ;
  65. ;    envp -  pointer to environment block (must be aligned on
  66. ;        paragraph boundary). Unused if envlen is 0.
  67. ;
  68. ;    'cmdtail' and 'execfname' must be zero terminated, even when
  69. ;    calling from Pascal. For Pascal, the length byte of the string
  70. ;    is ignored.
  71. ;
  72. ;   Returns:
  73. ;    0000..00ff:    Returncode of EXECed program
  74. ;    03xx:        DOS-Error xx calling EXEC
  75. ;    0500:        Swapping requested, but prep_swap has not 
  76. ;            been called or returned an error
  77. ;    0501:        MCBs don't match expected setup
  78. ;    0502:        Error while swapping out
  79. ;    06xx:        DOS-Error xx on redirection
  80. ;
  81. ;
  82. ; For swapping, the swap method must be prepared before calling do_spawn.
  83. ;
  84. ;   PASCAL:
  85. ;    function prep_swap (method: word; swapfname: string): integer;
  86. ;   C:
  87. ;    int prep_swap (unsigned method, char *swapfname)
  88. ;
  89. ;   Parameters:
  90. ;
  91. ;    method    - bit-map of allowed swap devices:
  92. ;            01 - Allow EMS
  93. ;            02 - Allow XMS
  94. ;            04 - Allow File swap
  95. ;            10 - Try XMS first, then EMS
  96. ;            40 - Create file as "hidden"
  97. ;            80 - Use "create temp" call for file swap
  98. ;               100 - Don't preallocate file
  99. ;               200 - Check for Network, don't preallocate if net
  100. ;              4000 - Environment block will not be swapped
  101. ;
  102. ;    swapfname - swap file name (may be undefined if the
  103. ;            "method" parameters disallows file swap).
  104. ;            The string must be zero terminated, even
  105. ;            when calling from Pascal. For Pascal, the 
  106. ;            length byte of the string is ignored.
  107. ;
  108. ;   Returns:
  109. ;
  110. ;       A positive integer on success:
  111. ;        1 - EMS swap initialized
  112. ;        2 - XMS swap initialized
  113. ;        4 - File swap initialized
  114. ;    A negative integer on failure:
  115. ;        -1 - Couldn't allocate swap space
  116. ;        -2 - The spawn module is located too low in memory
  117. ;<
  118. ;>d
  119. ; Assemblierung mit
  120. ;
  121. ; tasm  /DPASCAL spawn,spawnp          - Turbo Pascal (nur Tasm), near
  122. ; tasm  /DPASCAL /DFARCALL spawn,spawnp    - Turbo Pascal (nur Tasm), far
  123. ; ?asm  spawn;                  - C, default model (small)
  124. ; ?asm  /DMODL=large spawn          - C, large model
  125. ;
  126. ;    HINWEIS: Für C können Sie entweder die folgende 'model'-Direktive
  127. ;        Ihrem Speichermodell entsprechend ändern, oder beim
  128. ;        Assemblieren MODL=xxx in der Kommandozeile definieren.
  129. ;
  130. ;        Für Turbo C Huge model müssen Sie /DTC_HUGE beim Assemblieren
  131. ;        angeben, oder das Symbol in dieser Quelle definieren.
  132. ;
  133. ;
  134. ; Haupfunktion:
  135. ;
  136. ;   PASCAL:
  137. ;       function do_spawn (swapping: integer; 
  138. ;                  execfname: string;
  139. ;               cmdtail: string; 
  140. ;                  envlen: word; 
  141. ;               var envp)
  142. ;
  143. ;   C:
  144. ;       int do_spawn (int swapping,
  145. ;              char *execfname, 
  146. ;              char *cmdtail,
  147. ;              unsigned envlen, 
  148. ;              char *envp)
  149. ;
  150. ;   Parameter:
  151. ;
  152. ;    swapping - swap/spawn/exec Funktion:
  153. ;            < 0: Exec, kein Auslagern, keine Rückkehr
  154. ;                0: Spawn, kein Auslagern
  155. ;            > 0: Spawn, Auslagern
  156. ;                 in diesem Fall muß vor Aufruf die Funktion
  157. ;                 prep_swap aufgerufen worden sein (siehe unten).
  158. ;
  159. ;    cmdtail - Parameter für das aufgerufene Programm.
  160. ;
  161. ;    execfname - Name und Pfad des auszuführenden Programms.
  162. ;
  163. ;    envlen - Länge der Umgebungsvariablen-Kopie (kann 0 sein).
  164. ;
  165. ;    envp -  Zeiger auf Umgebungsvariablen-Block (muß auf Paragraph-
  166. ;        Grenze adjustiert sein). Wird nicht benutzt wenn der
  167. ;        envlen Parameter 0 ist.
  168. ;
  169. ;    'cmdtail' und 'execfname' müssen 0-Terminiert sein, selbst wenn
  170. ;    der Aufruf von Pascal erfolgt. Bei Aufruf von Pascal wird das
  171. ;    Längenbyte am Anfang des Strings ignoriert.
  172. ;
  173. ;   Liefert:
  174. ;
  175. ;    0000..00ff:    Returncode des ausgeführten Programms
  176. ;    03xx:        DOS-Fehler xx beim Aufruf von EXEC
  177. ;    0500:        Auslagern angefordert, aber prep_swap wurde
  178. ;            nicht aufgerufen oder nicht erfolgreich ausgeführt
  179. ;    0501:        MCBs sind fehlerhaft bzw. verändert
  180. ;    0502:        Fehler bei Auslagerung
  181. ;    06xx:        DOS-Fehler xx bei Redirection
  182. ;
  183. ;
  184. ; Um Auslagern zu können, muß die Auslagerungs-Methode vor Aufruf von
  185. ; do_spawn vorbereitet werden.
  186. ;
  187. ;   PASCAL:
  188. ;    function prep_swap (method: byte; swapfname: string): integer;
  189. ;   C:
  190. ;    int prep_swap (unsigned char method, char *swapfname)
  191. ;
  192. ;   Parameter:
  193. ;
  194. ;    method    - Bit-Map der zulässigen Auslagerungsziele und Optionen:
  195. ;            01 - EMS zulassen
  196. ;            02 - XMS zulassen
  197. ;            04 - Datei zulassen
  198. ;            10 - Erst XMS, dann EMS versuchen
  199. ;            40 - Datei "hidden" erzeugen
  200. ;            80 - "create temp" Funktion bei Datei-Auslagerung
  201. ;               100 - Datei nicht präallozieren
  202. ;               200 - Netzwerk prüfen, nicht präallozieren wenn Netz
  203. ;              4000 - Environmentblock nicht auslagern
  204. ;
  205. ;    swapfname - Auslagerungsdateiname bzw. Pfad (kann undefiniert
  206. ;            sein wenn der "Method" Parameter keine Dateiauslagerung
  207. ;            zulässt).
  208. ;            Der String muß 0-Terminiert sein, selbst wenn
  209. ;            der Aufruf von Pascal erfolgt. Bei Aufruf von Pascal 
  210. ;            wird das Längenbyte am Anfang des Strings ignoriert.
  211. ;
  212. ;   Liefert:
  213. ;
  214. ;       Einen positiven Wert bei Erfolg:
  215. ;        1 - EMS Auslagerung initialisiert
  216. ;        2 - XMS Auslagerung initialisiert
  217. ;        4 - Datei-Auslagerung initialisiert
  218. ;    Einen negativen Wert bei Fehler:
  219. ;        -1 - Kein Platz für Auslagerung
  220. ;        -2 - Das "spawn"-Modul ist zu nah am Beginn des Programms
  221. ;<
  222. ;--------------------------------------------------------------------------
  223. ;
  224. ;>e
  225. ;    Set NO_INHERIT to FALSE if you don't want do_exec to mess with
  226. ;    the handle table in the PSP, and/or you do want the child process
  227. ;    to inherit all open files.
  228. ;    If NO_INHERIT is TRUE, only the first five handles (the standard
  229. ;    ones) will be inherited, all others will be hidden. This allows
  230. ;    the child to open more files, and also protects you from the child
  231. ;    messing with any open handles.
  232. ;    NO_INHERIT should always be TRUE if you use functions to extend
  233. ;    the handle table (for more than 20 open files).
  234. ;
  235. ;    Set REDIRECT to FALSE if you do not want do_spawn to support redirection.
  236. ;
  237. ;    The following defines are for Turbo Pascal only:
  238. ;        Set PAS_FREE to TRUE to not swap the unused heap space.
  239. ;        Set TPAS_6 to TRUE for Turbo Pascal version 6.
  240. ;
  241. ;    When PAS_FREE is TRUE, the unused heap, i.e. the space between
  242. ;    HeapPtr and FreePtr for TP 5.x, or the space between HeapPtr and
  243. ;    HeapEnd for TP6.x, is temporarily chained into the DOS free space 
  244. ;    list, and is not swapped out. Depending on your applications heap 
  245. ;    usage, this can save a large amount of swap space, and considerably
  246. ;    speed up the swap.
  247. ;<
  248. ;>d
  249. ;    Setzen Sie NO_INHERIT auf FALSE wenn Sie nicht wollen, daß do_spawn
  250. ;    die Handle-Tabelle im PSP modifiziert, und/oder der Kindprozess
  251. ;    alle offenen Dateien erben soll.
  252. ;    Wenn NO_INHERIT TRUE ist, werden nur die ersten fünf Handles
  253. ;    (die Standard-Handles) vererbt, alle anderen werden versteckt.
  254. ;    Dies erlaubt dem Kindprozess, mehr Dateien zu öffnen, und schützt
  255. ;    Sie außerdem vor Änderungen an offenen Dateien.
  256. ;    NO_INHERIT sollte stets TRUE sein, wenn Sie Funktionen zur
  257. ;    Erweiterung der Handle-Tabelle (für mehr als 20 offene Dateien)
  258. ;    benutzen.
  259. ;
  260. ;    Setzen Sie REDIRECT auf FALSE wenn do_spawn keine Dateiumleitung 
  261. ;    unterstützen soll.
  262. ;
  263. ;    Die folgenden Definitionen werden nur für Turbo Pascal benötigt:
  264. ;        Setzen Sie PAS_FREE auf TRUE wenn der unbenutzte Heap
  265. ;        nicht ausgelagert werden soll.
  266. ;        Setzen Sie TPAS_6 auf TRUE für Turbo Pascal Version 6.
  267. ;
  268. ;    Wenn PAS_FREE TRUE ist, wird der nicht belegte Heap, d.h. der
  269. ;    Bereich zwischen HeapPtr und FreePtr für TP 5.x, bzw. zwischen
  270. ;    HeapPtr und HeapEnd für TP 6.x, temporär in die DOS-Freispeicher-
  271. ;    Liste eingefügt, und damit nicht ausgelagert. Abhängig von der
  272. ;    Heap-Belegung Ihrer Applikation kann dies den Speicherbedarf
  273. ;    für die Auslagerung wesentlich verringern, und die Auslagerung
  274. ;    beschleunigen.
  275. ;<
  276. ;
  277. FALSE        =    0
  278. TRUE        =    NOT FALSE
  279. ;
  280. NO_INHERIT    =    TRUE
  281. REDIRECT    =    TRUE
  282. ;
  283. PAS_FREE    =    FALSE
  284. TPAS_6        =    FALSE
  285. ;
  286. ;
  287.     IFDEF    PASCAL
  288.     .model    tpascal
  289.     IFDEF    FARCALL
  290.     %out    Pascal, far calls
  291.     ELSE
  292.     %out    Pascal, near calls
  293.     ENDIF
  294. ;
  295.     extrn    prefixseg: word
  296.     IF    PAS_FREE
  297.     extrn    HeapPtr: dword
  298.     IF    TPAS_6
  299.     extrn    HeapEnd: dword
  300.     ELSE
  301.     extrn    FreePtr: dword
  302.     ENDIF
  303.     ENDIF
  304. ;
  305. ptrsize    =    1
  306.     ELSE
  307.     IFNDEF    MODL
  308.     .model    small,c
  309.     %out    small model
  310.     ELSE
  311. %    .model    MODL,c
  312. %    %out    MODL model
  313.     ENDIF
  314. ;
  315. ptrsize    =    @DataSize
  316. ;
  317.     extrn    _psp: word
  318.     ENDIF
  319. ;
  320.     public    do_spawn
  321.     public    prep_swap
  322.     IFNDEF    PASCAL
  323.     public    swap_prep
  324.     ENDIF
  325. ;
  326. stacklen    =    256        ;e local stack
  327.                     ;d Lokaler Stack
  328. ;
  329. ;e    "ems_size" is the EMS block size: 16k.
  330. ;d    "ems_size" ist die EMS-Blockgröße: 16k.
  331. ;
  332. ems_size    =    16 * 1024    ;e EMS block size
  333.                     ;d EMS-Seiten-Größe
  334. ems_parasize    =    ems_size / 16    ;e same in paragraphs
  335.                     ;d desgleichen in Paragraphen
  336. ems_shift    =    10        ;e shift factor for paragraphs
  337.                     ;d Schiebefaktor für Paragraphen
  338. ems_paramask    =    ems_parasize-1    ;e block mask
  339.                     ;d Maske für Paragraphen
  340. ;
  341. ;e    "xms_size" is the unit of measurement for XMS: 1k
  342. ;d    "xms_size" ist die Blockgröße für XMS: 1k
  343. ;
  344. xms_size    =    1024        ;e XMS block size
  345.                     ;d XMS-Block-Größe
  346. xms_parasize    =    xms_size / 16    ;e same in paragraphs
  347.                     ;d desgleichen in Paragraphen
  348. xms_shift    =    6        ;e shift factor for paragraphs
  349.                     ;d Schiebefaktor für Paragraphen
  350. xms_paramask    =    xms_parasize-1    ;e block mask
  351.                     ;d Maske für Paragraphen
  352. ;
  353. ;e    Method flags
  354. ;d    Auslagerungsmethoden-Flags
  355. ;
  356. USE_EMS        =    01h
  357. USE_XMS        =    02h
  358. USE_FILE    =    04h
  359. XMS_FIRST    =    10h
  360. HIDE_FILE    =    40h
  361. CREAT_TEMP    =    80h
  362. NO_PREALLOC    =    100h
  363. CHECK_NET    =    200h
  364. DONT_SWAP_ENV    =    4000h
  365. ;
  366. ;e    Return codes
  367. ;d    Resultatcodes
  368. ;
  369. RC_TOOLOW    =    0102h
  370. RC_BADPREP    =    0500h
  371. RC_MCBERROR    =    0501h
  372. RC_SWAPERROR    =    0502h
  373. RC_REDIRFAIL    =    0600h
  374. ;
  375. EMM_INT        =    67h
  376. ;
  377. ;e    The EXEC function parameter block
  378. ;d    Der Parameterblock für die EXEC-Funktion
  379. ;
  380. exec_block    struc
  381. envseg    dw    ?        ;e environment segment
  382.                 ;d Segmentadresse Umgebungsvariablenblock
  383. ppar    dw    ?        ;e program parameter string offset
  384.                 ;d Programmparameterstring Offset
  385. pparseg    dw    ?        ;e program parameter string segment
  386.                 ;d Programmparameterstring Segment
  387. fcb1    dw    ?        ; FCB offset
  388. fcb1seg    dw    ?        ; FCB segment
  389. fcb2    dw    ?        ; FCB offset
  390. fcb2seg    dw    ?        ; FCB segment
  391. exec_block    ends
  392. ;
  393. ;e    Structure of an XMS move control block
  394. ;d    Struktur eines XMS move Kontrollblocks
  395. ;
  396. xms_control    struc
  397. lenlo        dw    ?    ;e length to move (doubleword)
  398.                 ;d Länge für Move (Doppelwort)
  399. lenhi        dw    ?
  400. srchnd        dw    ?    ;e source handle (0 for standard memory)
  401.                 ;d Quell-Handle (0 für Standardspeicher)
  402. srclo        dw    ?    ;e source address (doubleword or seg:off)
  403.                 ;d Quell-Adresse (Doppelwort oder seg:off)
  404. srchi        dw    ?
  405. desthnd        dw    ?    ;e destination handle (0 for standard memory)
  406.                 ;d Ziel-Handle (0 für Standardspeicher)
  407. destlo        dw    ?    ;e destination address (doubleword or seg:off)
  408.                 ;d Ziel-Adresse (Doppelwort oder seg:off)
  409. desthi        dw    ?
  410. xms_control    ends
  411. ;
  412. ;e    The structure of the start of an MCB (memory control block)
  413. ;d    Die Struktur des Beginns eines MCB (Speicher-Kontrollblock)
  414. ;
  415. mcb        struc
  416. id        db    ?
  417. owner        dw    ?
  418. paras        dw    ?
  419. mcb        ends
  420. ;>e
  421. ;    The structure of an internal MCB descriptor.
  422. ;    CAUTION: This structure is assumed to be no larger than 16 bytes
  423. ;    in several places in the code, and to be exactly 16 bytes when
  424. ;    swapping in from file. Be careful when changing this structure.
  425. ;<
  426. ;>d
  427. ;    Die Struktur eines internen MCB-Descriptors.
  428. ;    ACHTUNG: An mehreren Stellen im Code wird angenommen, daß die
  429. ;    Länge dieser Struktur 16 Bytes nicht überschreitet. Beim
  430. ;    Zurücklesen von Datei wird angenommen, daß die Länge exakt 16
  431. ;    Bytes beträgt. Bei Änderungen in dieser Struktur ist daher
  432. ;    Vorsicht geboten.
  433. ;<
  434. mcbdesc        struc
  435. addr        dw    ?    ;e paragraph address of the MCB
  436.                 ;d Paragraph-Adresse des MCB
  437. msize        dw    ?    ;e size in paragraphs (excluding header)
  438.                 ;d Größe in Paragraphen (Ausschließlich Header)
  439. swoffset    dw    ?    ;e swap offset (0 in all blocks except first)
  440.                 ;d Auslagerungs-Offset (0 in allen Blöcken 
  441.                 ;d außer dem ersten)
  442. swsize        dw    ?    ;e swap size (= msize + 1 except in first)
  443.                 ;d Auslagerungsgröße (= msize + 1 außer
  444.                 ;d im ersten Block)
  445. num_follow    dw    ?    ;e number of following MCBs
  446.                 ;d Zahl der folgenden MCBs
  447.         dw    3 dup(?) ;e pad to paragraph (16 bytes)
  448.                  ;d Auffüllen auf Paragraphen (16 Bytes)
  449. mcbdesc        ends
  450. ;
  451. ;e    The variable block set up by prep_swap
  452. ;d    Der Variablenblock der durch prep_swap initialisiert wird
  453. ;
  454. prep_block    struc
  455. xmm        dd    ?        ;e XMM entry address
  456.                     ;d Einsprungadresse XMM
  457. first_mcb    dw    ?        ;e Segment of first MCB
  458.                     ;d Segment des ersten MCB
  459. psp_mcb        dw    ?        ;e Segment of MCB of our PSP
  460.                     ;d Segment des MCB unseres PSP
  461. env_mcb        dw    ?        ;e MCB of Environment segment
  462.                     ;d MCB des Umgebungsvariablenblocks
  463. noswap_mcb    dw    ?        ;e Env MCB that may not be swapped
  464.                     ;d Env MCB der nicht Ausgelagert wird
  465.         IF    NOT NO_INHERIT
  466. noswap_mcb2    dw    ?        ;e Handle MCB that may not be swapped
  467.                     ;d Handle MCB der nicht Ausgelagert wird
  468.         ENDIF
  469.         IFDEF    PASCAL
  470.         IF    PAS_FREE
  471. pmemid        db    ?
  472. pmempar        dw    ?
  473.         ENDIF
  474.         ENDIF
  475. ems_pageframe    dw    ?        ;e EMS page frame address
  476.                     ;d EMS-Seiten-Adresse
  477. handle        dw    ?        ;e EMS/XMS/File handle
  478.                     ;d Handle für EMS/XMS/Datei
  479. total_mcbs    dw    ?        ;e Total number of MCBs
  480.                     ;d Gesamtzahl MCBs
  481. swapmethod    db    ?        ;e Method for swapping
  482.                     ;d Auslagerungsmethode
  483. swapfilename    db    81 dup(?)    ;e Swap file name if swapping to file
  484.                     ;d Auslagerungsdateiname
  485. prep_block    ends
  486. ;
  487. ;----------------------------------------------------------------------
  488. ;>e
  489. ;    Since we'll be moving code and data around in memory,
  490. ;    we can't address locations in the resident block with
  491. ;    normal address expressions. MASM does not support
  492. ;    defining variables with a fixed offset, so we have to resort
  493. ;    to a kludge, and define the shrunk-down code as a structure.
  494. ;    It would also be possible to use an absolute segment for the
  495. ;    definition, but this is not supported by the Turbo Pascal linker.
  496. ;
  497. ;    All references to low-core variables from low-core itself 
  498. ;    are made through DS, so we define a text macro "lmem" that 
  499. ;    expands to "ds:". When setting up low core from the normal
  500. ;    code, ES is used to address low memory, so this can't be used.
  501. ;<
  502. ;>d
  503. ;    Da Code und Daten in andere Speicherbereiche kopiert werden,
  504. ;    können Adressen im residenten Teil nicht mit normalen Adress-
  505. ;    ausdrücken angesprochen werden. MASM unterstützt leider nicht
  506. ;    die Definition von Variablen mit festen Offsets, sodaß wir
  507. ;    den residenten Teil als Struktur definieren müssen. Eine Definition
  508. ;    als absolutes Segment wäre zwar in MASM möglich, dies wird jedoch
  509. ;    vom Turbo Pascal Linker nicht unterstützt.
  510. ;
  511. ;    Alle Referenzen auf Variablen im residenten Teil von diesem
  512. ;    Teil selbst geschehen über DS, hierfür kann daher ein Text-Makro
  513. ;    "lmem" definiert werden, das zu "ds:" expandiert wird. Beim
  514. ;    Aufsetzen des residenten Teils vom normalen Programm geschieht
  515. ;    die Adressierung über ES, sodaß dieses Makro dort nicht verwendet
  516. ;    werden darf.
  517. ;<
  518. lmem    equ    <ds:>
  519. ;>e
  520. ;    The memory structure for the shrunk-down code, excluding the
  521. ;    code itself. The code follows this block.
  522. ;    The start of this block is the PSP.
  523. ;<
  524. ;>d
  525. ;    Die Struktur des residenten Teils, ausschließlich des Programm-
  526. ;    Codes. Der Programmcode folgt diesem Block.
  527. ;    Der Beginn dieses Blocks ist der PSP.
  528. ;<
  529. parseg        struc
  530.         db    18h dup(?)
  531. psp_handletab    db    20 dup(?)    ; Handle Table
  532. psp_envptr    dw    ?        ; Environment Pointer
  533.         dd    ?
  534. psp_handlenum    dw    ?        ; Number of Handles (DOS >= 3.3)
  535. psp_handleptro    dw    ?        ; Handle Table Pointer (DOS >= 3.3)
  536. psp_handleptrs    dw    ?        ; Handle Table Pointer Segment
  537.         db    5ch-38h dup(?)    ;e start after PSP
  538.                     ;d Start nach PSP
  539. ;
  540. save_ss        dw    ?        ;e 5C - saved global ss
  541.                     ;d 5C - Sicherung globales SS
  542. save_sp        dw    ?        ;e 5E - saved global sp
  543.                     ;d 5E - Sicherung globaler SP
  544. xfcb1        db    16 dup(?)    ;e 60..6F - default FCB
  545.                     ;d 60..6F - Standard-FCB
  546. xfcb2        db    16 dup(?)    ;e 70..7F - default FCB
  547.                     ;d 70..7f - Standard-FCB
  548. zero        dw    ?        ;e 80 Zero command tail length (dummy)
  549.                     ;d 80 Null-Kommandozeile (Dummy)
  550. ;
  551. expar        db    TYPE exec_block dup (?) ; exec-parameter-block
  552. spx        dw    ?        ;e saved local sp
  553.                     ;d Sicherung lokaler SP
  554. div0_off    dw    ?        ;e divide by zero vector save
  555.                     ;d Sicherung divide-by-zero Vektor
  556. div0_seg    dw    ?
  557.         IF    NO_INHERIT
  558. lhandlesave    db    26 dup(?)    ;e saved handle table and pointer
  559.                     ;d Sicherung Handle-Tabelle und Pointer
  560.         IF    REDIRECT
  561. lredirsav    db    6 dup(?)    ;e saved redirection handles
  562.                     ;d Sicherung Umleitungs-Handles
  563.         ENDIF
  564.         ENDIF
  565.         IF    REDIRECT
  566. lstdinsav    dw    3 dup(?)    ;e duped redirection handles
  567.                     ;d Umleitungs-Handles aus 'dup'
  568.         ENDIF
  569. filename    db    82 dup(?)    ;e exec filename
  570.                     ;d EXEC-Dateiname
  571. progpars    db    128 dup(?)    ;e command tail
  572.                     ;d Kommandozeile
  573.         db    stacklen dup(?)    ;e local stack space
  574.                     ;d Lokaler Stackbereich
  575. mystack        db    ?
  576. lprep        db    TYPE prep_block dup(?)    ;e the swapping variables
  577.                         ;d die Auslagerungsvariablen
  578. lcurrdesc    db    TYPE mcbdesc dup(?)    ;e the current MCB descriptor
  579.                         ;d Descriptor aktueller MCB
  580. lxmsctl        db    TYPE xms_control dup(?)
  581. eretcode    dw    ?        ;e EXEC return code
  582.                     ;d Resultatcode EXEC
  583. retflags    dw    ?        ;e EXEC return flags
  584.                     ;d Resultatflags EXEC
  585. cgetmcb        dw    ?        ;e address of get_mcb
  586.                     ;d Adresse von get_mcb
  587. ;
  588. parseg    ends
  589. ;
  590. param_len    =    ((TYPE parseg + 1) / 2) * 2    ; make even
  591. codebeg        =    param_len
  592. ;
  593.     .code
  594. ;
  595. ;------------------------------------------------------------------------
  596. ;
  597. lowcode_begin:
  598. ;>e
  599. ;       The following parts of the program code will be moved to
  600. ;    low core and executed there, so there must be no absolute 
  601. ;    memory references.
  602. ;    The call to get_mcb must be made indirect, since the offset
  603. ;    from the swap-in routine to get_mcb will not be the same
  604. ;    after moving.
  605. ;
  606. ;
  607. ;    get_mcb allocates a block of memory by modifying the MCB chain
  608. ;    directly.
  609. ;
  610. ;    On entry, lcurrdesc has the mcb descriptor for the block to
  611. ;          allocate.
  612. ;
  613. ;    On exit,  Carry is set if the block couldn't be allocated.
  614. ;
  615. ;    Uses     AX, BX, CX, ES
  616. ;    Modifies lprep.first_mcb
  617. ;<
  618. ;>d
  619. ;       Der folgende Teil des Programm-Codes wird in den unteren Speicher-
  620. ;    bereich kopiert und dort ausgeführt, es dürfen daher keine
  621. ;    absoluten Speicheradressen verwendet werden.
  622. ;    Der Aufruf von get_mcb muß indirekt erfolgen, da der Offset
  623. ;    der Einlagerungs-Routine zu get_mcb nach dem Kopieren nicht
  624. ;    mehr mit der Definition übereinstimmt.
  625. ;
  626. ;
  627. ;    get_mcb alloziert einen Speicherblock durch direkte Modifikation
  628. ;        der MCB-Kette.
  629. ;
  630. ;    Bei Einsprung enthält lcurrdesc den Deskriptor für den zu
  631. ;        allozierenden Block.
  632. ;
  633. ;    Bei Rückkehr ist das Carry-Flag gesetzt wenn der Block nicht
  634. ;        alloziert werden konnte.
  635. ;
  636. ;    Benutzt    AX, BX, CX, ES
  637. ;    Modifiziert lprep.first_mcb
  638. ;<
  639. get_mcb    proc    near
  640. ;
  641.     mov    ax,lmem lprep.first_mcb
  642.     mov    bx,lmem lcurrdesc.addr
  643. ;
  644. getmcb_loop:
  645.     mov    es,ax
  646.     cmp    ax,bx
  647.     ja    gmcb_abort        ;e halt if MCB > wanted
  648.                     ;d Abbrechen wenn MCB > gewünschtem
  649.     je    mcb_found        ;e jump if same addr as wanted
  650.                     ;d jump wenn Adresse gleich gewünschter
  651.     add    ax,es:paras        ;e last addr
  652.                     ;d Letze Adresse
  653.     inc    ax            ; next mcb
  654.     cmp    ax,bx
  655.     jbe    getmcb_loop        ;e Loop if next <= wanted
  656.                     ;d Nochmal wenn nächster <= gewünschter
  657. ;
  658. ;>e
  659. ;    The wanted MCB starts within the current MCB. We now have to
  660. ;    create a new MCB at the wanted position, which is initially
  661. ;    free, and shorten the current MCB to reflect the reduced size.
  662. ;<
  663. ;>d
  664. ;    Der gewünschte MCB beginnt innerhalb des laufenden MCB. Es muß
  665. ;    nun ein MCB an der gewünschten Position eingerichtet werden, und
  666. ;    der laufende MCB ist zu kürzen.
  667. ;<
  668.     cmp    es:owner,0
  669.     jne    gmcb_abort        ;e halt if not free
  670.                     ;d Abbruch wenn nicht frei
  671.     mov    bx,es            ;e current
  672.                     ;d laufender
  673.     inc    bx            ;e + 1 (header doesn't count)
  674.                     ;d + 1 (Header zählt nicht)
  675.     mov    ax,lmem lcurrdesc.addr
  676.     sub    ax,bx            ;e paragraphs between MCB and wanted
  677.                     ;d Paragraphen zwischen MCB 
  678.                     ;d und gewünschtem
  679.     mov    bx,es:paras        ;e paras in current MCB
  680.                     ;d Paragraphen in laufendem MCB
  681.     sub    bx,ax            ;e remaining paras
  682.                     ;d Restliche Paragraphen
  683.     dec    bx            ;e -1 for header
  684.                     ;d -1 für Header
  685.     mov    es:paras,ax        ;e set new size for current
  686.                     ;d neue Größe für laufenden Setzen
  687.     mov    cl,es:id        ;e old id
  688.                     ;d Alte ID
  689.     mov    es:id,4dh        ;e set id: there is a next
  690.                     ;d Setze ID: es gibt einen nächsten
  691.     mov    ax,lmem lcurrdesc.addr
  692.     mov    es,ax
  693.     mov    es:id,cl        ;e and init to free
  694.                     ;d und initialisiere auf Frei
  695.     mov    es:owner,0
  696.     mov    es:paras,bx
  697. ;>e
  698. ;    We have found an MCB at the right address. If it's not free,
  699. ;    abort. Else check the size. If the size is ok, we're done 
  700. ;    (more or less).
  701. ;<
  702. ;>d
  703. ;    Wir haben einen MCB an der korrekten Adresse. Falls er nicht
  704. ;    frei ist, abbrechen. Sonst Größe prüfen. Falls die Größe
  705. ;    korrekt ist, sind wir (mehr oder weniger) fertig.
  706. ;<
  707. mcb_found:
  708.     mov    es,ax
  709.     cmp    es:owner,0
  710.     je    mcb_check        ;e continue if free
  711.                     ;d weiter wenn Frei
  712. ;
  713. gmcb_abort:
  714.     stc
  715.     ret
  716. ;
  717. mcb_check:
  718.     mov    ax,es:paras        ;e size
  719.                     ;d Größe
  720.     cmp    ax,lmem lcurrdesc.msize    ;e needed size
  721.                     ;d gewünschte Größe
  722.     jae    mcb_ok            ;e ok if enough space
  723.                     ;d OK wenn genug Platz
  724. ;>e
  725. ;    If there's not enough room in this MCB, check if the next
  726. ;    MCB is free, too. If so, coalesce both MCB's and check again.
  727. ;<
  728. ;>d
  729. ;    Wenn in diesem MCB nicht genug Platz ist, den nächsten MCB
  730. ;    prüfen ob er ebenfalls frei ist. Falls ja, beide Blöcke
  731. ;    kombinieren und nochmals prüfen.
  732. ;<
  733.     cmp    es:id,4dh
  734.     jnz    gmcb_abort        ;e halt if no next
  735.                     ;d Abbruch wenn kein nächster
  736.     push    es            ;e save current
  737.                     ;d Laufenden sichern
  738.     mov    bx,es
  739.     add    ax,bx
  740.     inc    ax            ;e next MCB
  741.                     ;d nächter MCB
  742.     mov    es,ax
  743.     cmp    es:owner,0        ;e next free ?
  744.                     ;d ist der nächste frei?
  745.     jne    gmcb_abort        ;e halt if not
  746.                     ;d Abbruch wenn nein
  747.     mov    ax,es:paras        ;e else load size
  748.                     ;d sonst Größe laden
  749.     inc    ax            ;e + 1 for header
  750.                     ;d + 1 für Header
  751.     mov    cl,es:id        ;e and load ID
  752.                     ;d und ID laden
  753.     pop    es            ;e back to last MCB
  754.                     ;d zurück zum letzten MCB
  755.     add    es:paras,ax        ;e increase size
  756.                     ;d Größe erhöhen
  757.     mov    es:id,cl        ;e and store ID
  758.                     ;d und ID abspeichern
  759.     jmp    mcb_check        ;e now try again
  760.                     ;d nochmal versuchen
  761. ;>e
  762. ;    The MCB is free and large enough. If it's larger than the
  763. ;    wanted size, create another MCB after the wanted.
  764. ;<
  765. ;>d
  766. ;    Der MCB ist frei und groß genug. Wenn er größer als die gewünschte
  767. ;    Größe ist, muß ein weiterer MCB nach dem gewünschten erzeugt werden.
  768. ;<
  769. mcb_ok:
  770.     mov    bx,es:paras
  771.     sub    bx,lmem lcurrdesc.msize
  772.     jz    mcb_no_next        ;e ok, no next to create
  773.                     ;d OK, kein neuer einzurichten
  774.     push    es
  775.     dec    bx            ;e size of next block
  776.                     ;d Größe des nächsten Blocks
  777.     mov    ax,es
  778.     add    ax,lmem lcurrdesc.msize
  779.     inc    ax            ;e next MCB addr
  780.                     ;d Adresse des nächsten MCB
  781.     mov    cl,es:id        ;e id of this block
  782.                     ;d ID dieses Blocks
  783.     mov    es,ax            ;e address next
  784.                     ;d nächsten adressieren
  785.     mov    es:id,cl        ;e store id
  786.                     ;d ID abspeichern
  787.     mov    es:paras,bx        ;e store size
  788.                     ;d Größe abspeichern
  789.     mov    es:owner,0        ;e and mark as free
  790.                     ;d und als frei markieren
  791.     pop    es            ;e back to old MCB
  792.                     ;d zurück zum alten MCB
  793.     mov    es:id,4dh        ;e mark next block present
  794.                     ;d markieren daß weiterer existiert
  795.     mov    ax,lmem lcurrdesc.msize    ;e and set size to wanted
  796.                     ;d und Größe auf gewünschte setzen
  797.     mov    es:paras,ax
  798. ;
  799. mcb_no_next:
  800.     mov    es:owner,cx        ;e set owner to current PSP
  801.                     ;d owner auf laufenden PSP setzen
  802. ;>e
  803. ;    Set the 'first_mcb' pointer to the current one, so we don't
  804. ;    walk through all the previous blocks the next time.
  805. ;    Also, check if the block we just allocated is the environment
  806. ;    segment of the program. If so, restore the environment pointer
  807. ;    in the PSP.
  808. ;<
  809. ;>d
  810. ;    Der 'first_mcb'-Pointer wird auf den aktuellen gesetzt,
  811. ;    damit beim nächsten Mal nicht wieder alle vorangegangenen
  812. ;    Blöcke abgelatscht werden müssen.
  813. ;    Außerdem wird der gerade allozierte Block geprüft, ob es der
  814. ;    Umgebungsvariablenblock des Programms ist. Wenn ja, wird der
  815. ;    entsprechende Pointer im PSP wiederhergestellt.
  816. ;<
  817.     mov    ax,es
  818.     mov    lmem lprep.first_mcb,ax
  819.     cmp    lmem lprep.env_mcb,ax
  820.     jne    getmcb_finis
  821.     inc    ax
  822.     mov    lmem psp_envptr,ax
  823. ;
  824. getmcb_finis:
  825.     clc
  826.     ret                ;e all finished (whew!)
  827.                     ;d endlich geschafft
  828. ;
  829. get_mcb    endp
  830. ;
  831. ;
  832. ireti:
  833.     iret
  834. ;
  835. ;>e
  836. ;    The actual EXEC call.
  837. ;    Registers on entry:
  838. ;        BX    = paragraphs to keep (0 if no swap)
  839. ;        CX     = length of environment to copy (words) or zero
  840. ;        DS:SI    = environment source
  841. ;        ES:DI    = environment destination
  842. ;        (ES = our low core code segment)
  843. ;
  844. ;
  845. ;    copy environment buffer down if present
  846. ;<
  847. ;>d
  848. ;    Der eigentliche EXEC Aufruf.
  849. ;    Register bei Einsprung:
  850. ;        BX    = Residente Paragraphen (0 wenn keine Auslagerung)
  851. ;        CX     = Länge des Umgebungsvariablenblocks in Worten oder 0
  852. ;        DS:SI    = Quelladresse Umgebungsvariablenblock
  853. ;        ES:DI    = Zieladresse Umgebungsvariablenblock
  854. ;        (ES = Adresse residenter Teil)
  855. ;
  856. ;
  857. ;    Umgebungsvariablenblock nach unten kopieren wenn vorhanden
  858. ;<
  859. doexec:
  860.     jcxz    noenvcpy
  861.     rep movsw
  862. ;
  863. noenvcpy:
  864.     push    es            ; DS = ES = low core = PSP
  865.     pop    ds
  866.     or    bx,bx
  867.     jz    no_shrink
  868. ;
  869. ;e    first, shrink the base memory block down.
  870. ;d    Zuerst den Basisblock reduzieren.
  871. ;
  872.         mov    ah,04ah
  873.     int     21h                     ; resize memory block
  874. ;>e
  875. ;    Again walk all MCBs. This time, all blocks owned by the 
  876. ;    current process are released.
  877. ;<
  878. ;>d
  879. ;    Wieder mal alle MCBs durchgehen. Diesmal werden alle Blöcke 
  880. ;    die zu diesem Prozeß gehören freigegeben.
  881. ;<
  882.     mov    si,lmem lprep.first_mcb
  883.     or    si,si
  884.     jz    no_shrink
  885.     mov    dx,lmem lprep.psp_mcb
  886.     mov    bx,dx
  887.     inc    bx            ; base PSP (MCB owner)
  888.     mov    di,lmem lprep.noswap_mcb
  889. ;
  890. free_loop:
  891.     cmp    si,dx
  892.     je    free_next        ;e don't free base block
  893.                     ;d Basisblock nicht freigeben
  894.     cmp    si,di
  895.     je    free_next
  896.  
  897.     IF    NOT NO_INHERIT
  898.     cmp    si,lmem lprep.noswap_mcb2
  899.     je    free_next
  900.     ENDIF
  901.  
  902.     mov    es,si
  903.     cmp    bx,es:owner        ;e our process?
  904.                     ;d unser Prozeß?
  905.     jne    free_next        ;e next if not
  906.                     ;d nächsten wenn nein
  907.     cmp    si,lmem lprep.env_mcb    ;e is this the environment block?
  908.                     ;d ist dies der Umgebungsvariablenblock?
  909.     jne    free_noenv
  910.     mov    ds:psp_envptr,0        ;e else clear PSP pointer
  911.                     ;d sonst PSP-pointer löschen
  912. ;
  913. free_noenv:
  914.     inc    si
  915.     mov    es,si
  916.     dec    si
  917.     mov    ah,049h            ;e free memory block
  918.                     ;d Speicher freigeben
  919.     int    21h
  920. ;
  921. free_next:
  922.     mov    es,si
  923.     cmp    es:id,4dh        ;e normal block?
  924.                     ;d Normaler Block?
  925.     jne    free_ready        ;e ready if end of chain
  926.                     ;d Fertig wenn Ende der Kette
  927.     add    si,es:paras        ;e start + length
  928.                     ;d Beginn + Länge
  929.     inc    si            ;e next MCB
  930.                     ;d Nächster MCB
  931.     jmp    free_loop
  932. ;
  933. free_ready:
  934.     mov    ax,ds
  935.     mov    es,ax
  936. ;
  937. no_shrink:
  938.     mov    dx,filename        ;e params for exec
  939.                     ;d Parameter für EXEC
  940.     mov    bx,expar
  941.     mov    ax,04b00h
  942.     int    21h            ; exec
  943. ;>e
  944. ;    Return from EXEC system call. Don't count on any register except
  945. ;    CS to be restored (DOS 2.11 and previous versions killed all regs).
  946. ;<
  947. ;>d
  948. ;    Rückkehr vom EXEC Aufruf. Alle Register außer CS können zerstört
  949. ;    sein (DOS-Versionen 2.11 und früher zerstörten auch SS und SP).
  950. ;<
  951.     mov    bx,cs
  952.     mov    ds,bx
  953.     mov    es,bx
  954.     cli
  955.     mov    ss,bx
  956.     mov    sp,lmem spx
  957.     sti
  958.     cld
  959.     mov    lmem eretcode,ax    ;e save return code
  960.                     ;d Resultatcode sichern
  961.     pushf
  962.     pop    bx
  963.     mov    lmem retflags,bx    ;e and returned flags
  964.                     ;d und die gelieferten Flags
  965. ;
  966. ;e    Cancel Redirection
  967. ;d    Dateiumleitung aufheben
  968. ;
  969.     IF    REDIRECT
  970.     IF    NO_INHERIT
  971.     mov    si,lredirsav
  972.     mov    di,psp_handletab+5
  973.     mov    cx,3
  974.     rep movsw
  975.     ENDIF
  976.     mov    si,lstdinsav
  977.     xor    cx,cx
  978. ;
  979. lredirclose:
  980.     lodsw
  981.     cmp    ax,-1
  982.     je    lredclosenext
  983.     mov    bx,ax
  984.     mov    ah,46h
  985.     int    21h
  986. ;
  987. lredclosenext:
  988.     inc    cx
  989.     cmp    cx,3
  990.     jb    lredirclose
  991.     ENDIF
  992. ;
  993.     cmp    lmem lprep.swapmethod,0
  994.     je    exec_memok
  995.     jg    exec_expand
  996. ;
  997. ;    Terminate.
  998. ;
  999.     test    lmem retflags,1        ; carry?
  1000.     jnz    exec_term        ;e use EXEc retcode if set
  1001.                     ;d Resultat von EXEC liefern wenn ja
  1002.     mov    ah,4dh            ;e else get program return code
  1003.                     ;d Sonst Resultat von Programm holen
  1004.     int    21h
  1005. ;
  1006. exec_term:
  1007.     mov    ah,4ch
  1008.     int    21h
  1009. ;
  1010. ;
  1011. exec_expand:
  1012.     mov    ah,4ah            ; expand memory
  1013.     mov    bx,lmem lcurrdesc.msize
  1014.     int    21h
  1015.     jnc    exec_memok
  1016.     mov    ax,4cffh
  1017.     int    21h            ;e terminate on error
  1018.                     ;d Abbrechen bei Fehler
  1019. ;
  1020. ;e    Swap memory back
  1021. ;d    Zurücklesen Speicher
  1022. ;
  1023.     nop
  1024. ;
  1025. exec_memok:
  1026. ;
  1027. ;e    FALL THROUGH to the appropriate swap-in routine
  1028. ;d    Weiter in der passenden Einlagerungsroutine
  1029. ;
  1030. ;
  1031. getmcboff    =    offset get_mcb - offset lowcode_begin
  1032. iretoff        =    offset ireti - offset lowcode_begin
  1033. doexec_entry    =    offset doexec - offset lowcode_begin
  1034. base_length    =    offset $ - offset lowcode_begin
  1035. ;
  1036. ;-----------------------------------------------------------------------
  1037. ;>e
  1038. ;    The various swap in routines follow. Only one of the routines
  1039. ;    is copied to low memory.
  1040. ;    Note that the routines are never actually called, the EXEC return
  1041. ;    code falls through. The final RET thus will return to the restored
  1042. ;    memory image.
  1043. ;
  1044. ;    On entry, DS must point to low core.
  1045. ;    On exit to the restored code, DS is unchanged.
  1046. ;
  1047. ;
  1048. ;    swapin_ems:    swap in from EMS.
  1049. ;<
  1050. ;>d
  1051. ;    Es folgen die verschiedenen Wiederherstellungsroutinen. Nur 
  1052. ;    eine der Routinen wird in den residenten Teil kopiert.
  1053. ;    Beachten Sie, daß die Routinen nicht tatsächlich aufgerufen
  1054. ;    werden, der Code nach dem EXEC-Aufruf läuft in sie hinein. Das
  1055. ;    abschließende RET kehrt daher in das wiederhergestellte Haupt-
  1056. ;    programm zurück.
  1057. ;
  1058. ;    Bei Einsprung zeight DS auf den Basis-PSP.
  1059. ;    Bei Rückkehr in das wiederhergestellte Programm ist DS unverändert.
  1060. ;
  1061. ;
  1062. ;    swapin_ems:    Wiederherstellen von EMS.
  1063. ;<
  1064. swapin_ems    proc    far
  1065. ;
  1066.     xor    bx,bx
  1067.     mov    si,ems_parasize
  1068.     mov    dx,lmem lprep.handle    ; EMS handle
  1069. ;
  1070. swinems_main:
  1071.     push    ds
  1072.     mov    cx,lmem lcurrdesc.swsize    ;e block length in paras
  1073.                         ;d Blocklänge in Paragraphen
  1074.     mov    di,lmem lcurrdesc.swoffset    ;e swap offset
  1075.                         ;d Lese-Offset
  1076.     mov    es,lmem lcurrdesc.addr        ;e segment to swap
  1077.                         ;d Lese-Segment
  1078.     mov    ds,lmem lprep.ems_pageframe    ; page frame address
  1079. ;
  1080.     mov    ax,ems_parasize        ;e max length
  1081.                     ;d Maximale Länge
  1082.     sub    ax,si            ;e minus current offset
  1083.                     ;d Minus laufender Offset
  1084.     jnz    swinems_ok        ;e go copy if nonzero
  1085.                     ;d Kopieren wenn nicht 0
  1086. ;
  1087. swinems_loop:
  1088.     mov    ax,4400h        ;e map in next page
  1089.                     ;d Nächste EMS-Page einmappen
  1090.     int    EMM_INT
  1091.     or    ah,ah
  1092.     jnz    swinems_error
  1093.     mov    si,0            ;e reset offset
  1094.                     ;d Offset zurücksetzen
  1095.     inc    bx            ;e bump up page number
  1096.                     ;d Seitennummer erhöhen
  1097.     mov    ax,ems_parasize        ;e max length to copy
  1098.                     ;d Maximale Länge
  1099. ;
  1100. swinems_ok:
  1101.     cmp    ax,cx            ;e length to copy
  1102.                     ;d zu kopierende Länge
  1103.     jbe    swinems_doit        ;e go do it if <= total length
  1104.                     ;d kopieren wenn <= Gesamtlänge
  1105.     mov    ax,cx            ;e else use total length
  1106.                     ;d sonst Gesamtlänge kopieren
  1107. ;
  1108. swinems_doit:
  1109.     sub    cx,ax            ;e subtract copy length from total
  1110.                     ;d Gesamtlänge -= kopierte Länge
  1111.     push    cx            ;e and save
  1112.                     ;d sichern
  1113.     push    ax            ;e save the copy length in paras
  1114.                     ;d Sichern Kopierlänge in Paragraphen
  1115.     push    si
  1116.     push    di
  1117.     mov    cl,3
  1118.     shl    ax,cl            ;e convert to number of words (!)
  1119.                     ;d Konvertieren in Anzahl Worte (!)
  1120.     inc    cl
  1121.     shl    si,cl            ;e convert to byte address
  1122.                     ;d In Byte-Adresse konvertieren
  1123.     mov    cx,ax
  1124.     rep movsw
  1125.     pop    di
  1126.     pop    si
  1127.     pop    cx            ;e copy length in paras
  1128.                     ;d Kopierlänge in Paragraphen
  1129.     mov    ax,es
  1130.     add    ax,cx            ;e add copy length to dest segment
  1131.                     ;d Kopierlänge auf Zielsegment
  1132.     add    si,cx            ;e and EMS page offset
  1133.                     ;d und EMS-Seiten-Offset addieren
  1134.     mov    es,ax
  1135.     pop    cx            ;e remaining length
  1136.                     ;d Restlänge
  1137.     or    cx,cx            ;e did we copy everything?
  1138.                     ;d Alles kopiert?
  1139.     jnz    swinems_loop        ;e go loop if not
  1140.                     ;d Nochmal wenn nein
  1141. ;
  1142.     pop    ds
  1143.     cmp    lmem lcurrdesc.num_follow,0    ;e another MCB?
  1144.                         ;d noch ein MCB?
  1145.     je    swinems_complete    ;e exit if not
  1146.                     ;d Fertig wenn nein
  1147. ;
  1148. ;e    Another MCB follows, read next mcb descriptor into currdesc
  1149. ;d    Ein weiterer MCB folgt, lesen MCB Deskriptor nach currdesc
  1150. ;
  1151.     cmp    si,ems_parasize
  1152.     jb    swinems_nonewpage    ;e no new block needed
  1153.                     ;d kein neuer Block nötig
  1154.     mov    ax,4400h        ; map page, phys = 0
  1155.     int    EMM_INT
  1156.     or    ah,ah
  1157.     jnz    swinems_error1
  1158.     mov    si,0
  1159.     inc    bx
  1160. ;
  1161. swinems_nonewpage:
  1162.     push    si
  1163.     push    ds
  1164.     mov    ax,ds
  1165.     mov    es,ax
  1166.     mov    ds,lmem lprep.ems_pageframe    ; page frame address
  1167.     mov    cl,4
  1168.     shl    si,cl            ;e convert to byte address
  1169.                     ;d in Byte-Adresse konvertieren
  1170.     mov    cx,TYPE mcbdesc
  1171.     mov    di,lcurrdesc
  1172.     rep movsb
  1173.     pop    ds
  1174.     pop    si
  1175.     inc    si            ;e one paragraph
  1176.                     ;d Einen Paragraphen
  1177. ;
  1178.     push    bx
  1179.     call    lmem cgetmcb
  1180.     pop    bx
  1181.     jc    swinems_error1
  1182.     jmp    swinems_main
  1183. ;
  1184. swinems_complete:
  1185.     mov    ah,45h            ;e release EMS pages
  1186.                     ;d Freigeben EMS-Speicher
  1187.     int    EMM_INT
  1188.     ret
  1189. ;
  1190. swinems_error:
  1191.     pop    ds
  1192. swinems_error1:
  1193.     mov    ah,45h            ;e release EMS pages on error
  1194.                     ;d Bei Fehler EMS freigeben
  1195.     int    EMM_INT
  1196.     mov    ax,4cffh
  1197.     int    21h            ; terminate
  1198. ;
  1199. swapin_ems    endp
  1200. ;
  1201. swinems_length    = offset $ - offset swapin_ems
  1202. ;
  1203. ;
  1204. ;e    swapin_xms:    swap in from XMS.
  1205. ;d    swapin_xms:    Wiederherstellen von XMS.
  1206. ;
  1207. swapin_xms    proc    far
  1208. ;
  1209.     mov    ax,lmem lprep.handle    ; XMS handle
  1210.     mov    lmem lxmsctl.srchnd,ax     ;e source is XMS
  1211.                     ;d Quelle ist XMS
  1212.     mov    lmem lxmsctl.desthnd,0     ;e dest is normal memory
  1213.                     ;d Ziel ist Standardspeicher
  1214.     mov    lmem lxmsctl.srclo,0
  1215.     mov    lmem lxmsctl.srchi,0
  1216. ;
  1217. swinxms_main:
  1218.     mov    ax,lmem lcurrdesc.swsize ;e size in paragraphs
  1219.                      ;d Größe in Paragraphen
  1220.     mov    cl,4
  1221.     rol    ax,cl            ;e size in bytes + high nibble
  1222.                     ;d Größe in Bytes + high nibble
  1223.     mov    dx,ax
  1224.     and    ax,0fff0h        ; low word
  1225.     and    dx,0000fh        ; high word
  1226.     mov    lmem lxmsctl.lenlo,ax    ;e into control block
  1227.                     ;d in den Kontrollblock
  1228.     mov    lmem lxmsctl.lenhi,dx
  1229.     mov    ax,lmem lcurrdesc.swoffset    ;e swap offset
  1230.                         ;d Lese-Offset
  1231.     mov    lmem lxmsctl.destlo,ax         ;e into control block
  1232.                         ;d in den Kontrollblock
  1233.     mov    ax,lmem lcurrdesc.addr        ;e segment to swap
  1234.                         ;d Lese-Segment
  1235.     mov    lmem lxmsctl.desthi,ax
  1236.     mov    si,lxmsctl
  1237.     mov    ah,0bh
  1238.     call    lmem lprep.xmm        ; move it
  1239.     or    ax,ax
  1240.     jz    swinxms_error
  1241.     mov    ax,lmem lxmsctl.lenlo    ;e adjust source addr
  1242.                     ;d Quelladresse adjustieren
  1243.     add    lmem lxmsctl.srclo,ax
  1244.     mov    ax,lmem lxmsctl.lenhi
  1245.     adc    lmem lxmsctl.srchi,ax
  1246. ;
  1247.     cmp    lmem lcurrdesc.num_follow,0    ;e another MCB?
  1248.                         ;d noch ein MCB?
  1249.     je    swinxms_complete
  1250. ;
  1251.     mov    lmem lxmsctl.lenlo,TYPE mcbdesc
  1252.     mov    lmem lxmsctl.lenhi,0
  1253.     mov    lmem lxmsctl.desthi,ds
  1254.     mov    lmem lxmsctl.destlo,lcurrdesc
  1255.     mov    si,lxmsctl
  1256.     mov    ah,0bh
  1257.     call    lmem lprep.xmm        ; move it
  1258.     or    ax,ax
  1259.     jz    swinxms_error
  1260.     add    lmem lxmsctl.srclo,16    ; one paragraph
  1261.     adc    lmem lxmsctl.srchi,0
  1262. ;
  1263.     call    lmem cgetmcb
  1264.     jc    swinxms_error
  1265.     jmp    swinxms_main
  1266. ;
  1267. swinxms_complete:
  1268.     mov    ah,0ah            ;e release XMS frame
  1269.                     ;d Freigeben XMS-Speicher
  1270.     mov    dx,lmem lprep.handle       ; XMS handle
  1271.     call    lmem lprep.xmm
  1272.     ret
  1273. ;
  1274. swinxms_error:
  1275.     mov    ah,0ah            ;e release XMS frame on error
  1276.                     ;d Bei Fehler XMS-Speicher freigeben
  1277.     call    lmem lprep.xmm
  1278.     mov    ax,4c00h
  1279.     int    21h
  1280. ;
  1281. swapin_xms    endp
  1282. ;
  1283. swinxms_length    = offset $ - offset swapin_xms
  1284. ;
  1285. ;
  1286. ;e    swapin_file:    swap in from file.
  1287. ;d    swapin_file:    Wiederherstellen von Datei.
  1288. ;
  1289. swapin_file    proc    far
  1290. ;
  1291.     mov    dx,lprep.swapfilename
  1292.     mov    ax,3d00h            ; open file
  1293.     int    21h
  1294.     jc    swinfile_error2
  1295.     mov    bx,ax                ; file handle
  1296. ;
  1297. swinfile_main:
  1298.     push    ds
  1299.     mov    cx,lmem lcurrdesc.swsize    ;e size in paragraphs
  1300.                         ;d Blocklänge in Paragraphen
  1301.     mov    dx,lmem lcurrdesc.swoffset    ; swap offset
  1302.     mov    ds,lmem lcurrdesc.addr        ; segment to swap
  1303. ;
  1304. swinfile_loop:
  1305.     mov    ax,cx
  1306.     cmp    ah,8h            ;e above 32k?
  1307.                     ;d mehr als 32k?
  1308.     jbe    swinfile_ok        ;e go read if not
  1309.                     ;d lesen wenn nein
  1310.     mov    ax,800h            ;e else read 32k
  1311.                     ;d sonst 32k lesen
  1312. ;
  1313. swinfile_ok:
  1314.     sub    cx,ax            ;e remaining length
  1315.                     ;d Restlänge
  1316.     push    cx            ;e save it
  1317.                     ;d sichern
  1318.     push    ax            ;e and save paras to read
  1319.                     ;d Sichern Länge in Paragraphen
  1320.     mov    cl,4
  1321.     shl    ax,cl            ;e convert to bytes
  1322.                     ;d Konvertieren in Anzahl Bytes
  1323.     mov    cx,ax
  1324.     mov    ah,3fh            ; read
  1325.     int    21h
  1326.     jc    swinfile_error
  1327.     cmp    ax,cx
  1328.     jne    swinfile_error
  1329.     pop    cx            ;e paras read
  1330.                     ;d Gelesene Paragraphen
  1331.     mov    ax,ds
  1332.     add    ax,cx            ;e bump up dest segment
  1333.                     ;d Add. Kopierlänge auf Zielsegment
  1334.     mov    ds,ax
  1335.     pop    cx            ;e remaining length
  1336.                     ;d Restlänge
  1337.     or    cx,cx            ;e anything left?
  1338.                     ;d Noch etwas übrig?
  1339.     jnz    swinfile_loop        ;e go loop if yes
  1340.                     ;d Nochmal wenn ja
  1341. ;
  1342.     pop    ds
  1343.     cmp    lmem lcurrdesc.num_follow,0    ; another MCB?
  1344.                         ;d noch ein MCB?
  1345.     je    swinfile_complete    ;e ready if not
  1346.                     ;d Fertig wenn nein
  1347.     mov    cx,16            ;e read one paragraph
  1348.                     ;d einen Paragraphen lesen
  1349.     mov    dx,lcurrdesc
  1350.     mov    ah,3fh
  1351.     int    21h
  1352.     jc    swinfile_error1
  1353.     cmp    ax,cx
  1354.     jne    swinfile_error1
  1355. ;
  1356.     push    bx
  1357.     call    lmem cgetmcb
  1358.     pop    bx
  1359.     jc    swinfile_error1
  1360.     jmp    swinfile_main
  1361. ;
  1362. ;
  1363. swinfile_complete:
  1364.     mov    ah,3eh            ; close file
  1365.     int    21h
  1366.     mov    dx,lprep.swapfilename
  1367.     mov    ah,41h            ; delete file
  1368.     int    21h
  1369.     ret
  1370. ;
  1371. swinfile_error:
  1372.     pop    cx
  1373.     pop    cx
  1374.     pop    ds
  1375. swinfile_error1:
  1376.     mov    ah,3eh            ; close file
  1377.     int    21h
  1378. swinfile_error2:
  1379.     mov    dx,lprep.swapfilename
  1380.     mov    ah,41h            ; delete file
  1381.     int    21h
  1382.     mov    ax,4cffh
  1383.     int    21h
  1384. ;
  1385. swapin_file    endp
  1386. ;
  1387. swinfile_length    = offset $ - offset swapin_file
  1388. ;
  1389. ;
  1390. ;e    swapin_none:    no swap, return immediately.
  1391. ;d    swapin_none:    Kein Wiederherstellen, nur Rückkehr.
  1392. ;
  1393. swapin_none    proc    far
  1394. ;
  1395.     ret
  1396. ;
  1397. swapin_none    endp
  1398. ;
  1399. ;
  1400.     IF    swinems_length GT swinxms_length
  1401. swcodelen    =    swinems_length
  1402.     ELSE
  1403. swcodelen    =    swinxms_length
  1404.     ENDIF
  1405.     IF    swinfile_length GT swcodelen
  1406. swcodelen    =    swinfile_length
  1407.     ENDIF
  1408. ;
  1409. swap_codelen    =    ((swcodelen + 1) / 2) * 2
  1410. ;
  1411. codelen        =    base_length + swap_codelen
  1412. reslen        =    codebeg + codelen
  1413. keep_paras    =    (reslen + 15) shr 4    ;e paragraphs to keep
  1414.                         ;d Residente Paragraphen
  1415. swapbeg        =    keep_paras shl 4    ;e start of swap space
  1416.                         ;d Beginn Auslagerungsbereich
  1417. savespace    =    swapbeg - 5ch    ;e length of overwritten area
  1418.                     ;d Länge überschriebener Bereich
  1419. ;
  1420. ;--------------------------------------------------------------------
  1421. ;
  1422.     IFDEF    PASCAL
  1423.     .data
  1424.     extrn    swap_prep: prep_block
  1425.     ELSE
  1426.     IFDEF    TC_HUGE
  1427.     .fardata?    my_data
  1428.     ELSE
  1429.     .data?
  1430.     ENDIF
  1431.     ENDIF
  1432. ;
  1433. ;>e
  1434. ;    Space for saving the part of the memory image below the
  1435. ;    swap area that is overwritten by our code.
  1436. ;<
  1437. ;>d
  1438. ;    Platz zum Sichern des Teils des Speichers der vom 
  1439. ;    Aus-/Einlagerungscode und den Variablen überschrieben wird.
  1440. ;<
  1441. save_dat    db    savespace dup(?)
  1442. ;>e
  1443. ;    Variables used while swapping out.
  1444. ;    The "swap_prep" structure is initialized by prep_swap.
  1445. ;<
  1446. ;>d
  1447. ;    Variablen zur Benutzung beim Auslagern.
  1448. ;    Die "swap_prep" Struktur wird durch prep_swap initialisiert.
  1449. ;<
  1450.     IFNDEF    PASCAL
  1451. swap_prep    prep_block    <>
  1452.     ENDIF
  1453. nextmcb        mcbdesc        <>
  1454. currdesc    mcbdesc        <>
  1455. xmsctl        xms_control    <>
  1456. ems_curpage    dw        ?    ;e current EMS page number
  1457.                     ;d Laufende Nummer EMS-Seite
  1458. ems_curoff    dw        ?    ;e current EMS offset (paragraph)
  1459.                     ;d Laufender EMS Offset (Paragraph)
  1460. ;
  1461. ;--------------------------------------------------------------------
  1462. ;       
  1463.     .code
  1464. ;>e
  1465. ;    swapout_ems:    swap out an MCB block to EMS.
  1466. ;
  1467. ;    Entry:    "currdesc"     contains description of block to swap
  1468. ;        "nextmcb"    contains MCB-descriptor of next block
  1469. ;                if currdesc.num_follow is nonzero
  1470. ;
  1471. ;    Exit:    0 if OK, != 0 if error, Zero-flag set accordingly.
  1472. ;
  1473. ;    Uses:    All regs excpt DS
  1474. ;<
  1475. ;>d
  1476. ;    swapout_ems:    Auslagern eines MCB nach EMS.
  1477. ;
  1478. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1479. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1480. ;                wenn currdesc.num_follow nicht 0 ist.
  1481. ;
  1482. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1483. ;
  1484. ;    Benutzt: Alle Register außer DS
  1485. ;<
  1486. swapout_ems    proc    near
  1487. ;
  1488.     push    ds
  1489.     mov    cx,currdesc.swsize    ;e block length in paras
  1490.                     ;d Blocklänge in Paragraphen
  1491.     mov    si,currdesc.swoffset    ; swap offset
  1492.     mov    dx,swap_prep.handle    ; EMS handle
  1493.     mov    bx,ems_curpage        ;e current EMS page
  1494.                     ;d laufende EMS Seite
  1495.     mov    di,ems_curoff        ;e current EMS page offset (paras)
  1496.                     ;d laufender EMS Offset (Paragraph)
  1497.     mov    es,swap_prep.ems_pageframe    ; page frame address
  1498.     mov    ds,currdesc.addr    ; segment to swap
  1499. ;
  1500.     mov    ax,ems_parasize        ;e max length
  1501.                     ;d Maximale Länge
  1502.     sub    ax,di            ;e minus current offset
  1503.                     ;d Minus laufender Offset
  1504.     jnz    swems_ok        ;e go copy if there's room
  1505.                     ;d Kopieren wenn noch Platz ist
  1506. ;
  1507. swems_loop:
  1508.     mov    ax,4400h        ;e map in next page
  1509.                     ;d Nächste EMS-Page einmappen
  1510.     int    EMM_INT
  1511.     or    ah,ah
  1512.     jnz    swems_error
  1513.     mov    di,0            ;e reset offset
  1514.                     ;d Offset zurücksetzen
  1515.     inc    bx            ;e bump up page number
  1516.                     ;d Seitennummer erhöhen
  1517.     mov    ax,ems_parasize        ;e max length to copy
  1518.                     ;d Maximale Länge
  1519. ;
  1520. swems_ok:
  1521.     cmp    ax,cx            ;e length to copy
  1522.                     ;d zu kopierende Länge
  1523.     jbe    swems_doit        ;e go do it if <= total length
  1524.                     ;d kopieren wenn <= Gesamtlänge
  1525.     mov    ax,cx            ;e else use total length
  1526.                     ;d sonst Gesamtlänge kopieren
  1527. ;
  1528. swems_doit:
  1529.     sub    cx,ax            ;e subtract copy length from total
  1530.                     ;d Gesamtlänge -= kopierte Länge
  1531.     push    cx            ;e and save
  1532.                     ;d sichern
  1533.     push    ax            ;e save the copy length in paras
  1534.                     ;d Sichern Kopierlänge in Paragraphen
  1535.     push    si
  1536.     push    di
  1537.     mov    cl,3
  1538.     shl    ax,cl            ;e convert to number of words (!)
  1539.                     ;d Konvertieren in Anzahl Worte (!)
  1540.     inc    cl
  1541.     shl    di,cl            ;e convert to byte address
  1542.                     ;d In Byte-Adresse konvertieren
  1543.     mov    cx,ax
  1544.     rep movsw
  1545.     pop    di
  1546.     pop    si
  1547.     pop    cx            ;e copy length in paras
  1548.                     ;d Kopierlänge in Paragraphen
  1549.     mov    ax,ds
  1550.     add    ax,cx            ;e add copy length to source segment
  1551.                     ;d Kopierlänge auf Zielsegment
  1552.     add    di,cx            ;e and EMS page offset
  1553.                     ;d und EMS-Seiten-Offset addieren
  1554.     mov    ds,ax
  1555.     pop    cx            ;e remaining length
  1556.                     ;d Restlänge
  1557.     or    cx,cx            ;e did we copy everything?
  1558.                     ;d Alles kopiert?
  1559.     jnz    swems_loop        ;e go loop if not
  1560.                     ;d Nochmal wenn nein
  1561. ;
  1562.     pop    ds
  1563.     cmp    currdesc.num_follow,0    ;e another MCB?
  1564.                     ;d noch ein MCB?
  1565.     je    swems_complete        ;e exit if not
  1566.                     ;d Fertig wenn nein
  1567. ;
  1568. ;e    Another MCB follows, append nextmcb to save block.
  1569. ;d    Ein weiterer MCB folgt, nextmcb an Block anfügen.
  1570. ;
  1571.     cmp    di,ems_parasize
  1572.     jb    swems_nonewpage        ;e no new block needed
  1573.                     ;d kein neuer Block nötig
  1574.     mov    ax,4400h        ; map page, phys = 0
  1575.     int    EMM_INT
  1576.     or    ah,ah
  1577.     jnz    swems_error1
  1578.     mov    di,0
  1579.     inc    bx
  1580. ;
  1581. swems_nonewpage:
  1582.     push    di
  1583.     mov    cl,4
  1584.     shl    di,cl            ;e convert to byte address
  1585.                     ;d in Byte-Adresse konvertieren
  1586.     mov    cx,TYPE mcbdesc
  1587.     mov    si,offset nextmcb
  1588.     rep movsb
  1589.     pop    di
  1590.     inc    di            ;e one paragraph
  1591.                     ;d Einen Paragraphen
  1592. ;
  1593. swems_complete:
  1594.     mov    ems_curpage,bx
  1595.     mov    ems_curoff,di
  1596.     xor    ax,ax
  1597.     ret
  1598. ;
  1599. swems_error:
  1600.     pop    ds
  1601. swems_error1:
  1602.     mov    ah,45h            ;e release EMS pages on error
  1603.                     ;d Bei Fehler EMS freigeben
  1604.     int    EMM_INT
  1605.     mov    ax,RC_SWAPERROR
  1606.     or    ax,ax
  1607.     ret
  1608. ;
  1609. swapout_ems    endp
  1610. ;
  1611. ;>e
  1612. ;    swapout_xms:    swap out an MCB block to XMS.
  1613. ;
  1614. ;    Entry:    "currdesc"     contains description of block to swap
  1615. ;        "nextmcb"    contains MCB-descriptor of next block
  1616. ;                if currdesc.num_follow is nonzero
  1617. ;
  1618. ;    Exit:    0 if OK, -1 if error, Zero-flag set accordingly.
  1619. ;
  1620. ;    Uses:    All regs excpt DS
  1621. ;<
  1622. ;>d
  1623. ;    swapout_xms:    Auslagern eines MCB nach XMS.
  1624. ;
  1625. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1626. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1627. ;                wenn currdesc.num_follow nicht 0 ist.
  1628. ;
  1629. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1630. ;
  1631. ;    Benutzt: Alle Register außer DS
  1632. ;<
  1633. swapout_xms    proc    near
  1634. ;
  1635.     push    ds
  1636.     pop    es
  1637.     mov    ax,currdesc.swsize    ;e size in paragraphs
  1638.                     ;d Größe in Paragraphen
  1639.     mov    cl,4
  1640.     rol    ax,cl            ;e size in bytes + high nibble
  1641.                     ;d Größe in Bytes + high nibble
  1642.     mov    dx,ax
  1643.     and    ax,0fff0h        ; low word
  1644.     and    dx,0000fh        ; high word
  1645.     mov    xmsctl.lenlo,ax        ; into control block
  1646.     mov    xmsctl.lenhi,dx
  1647.     mov    xmsctl.srchnd,0        ;e source is normal memory
  1648.                     ;d Quelle ist Standardspeicher
  1649.     mov    ax,currdesc.swoffset    ; swap offset
  1650.     mov    xmsctl.srclo,ax        ; into control block
  1651.     mov    ax,currdesc.addr    ; segment to swap
  1652.     mov    xmsctl.srchi,ax
  1653.     mov    ax,swap_prep.handle    ; XMS handle
  1654.     mov    xmsctl.desthnd,ax
  1655.     mov    si,offset xmsctl
  1656.     mov    ah,0bh
  1657.     call    swap_prep.xmm        ; move it
  1658.     or    ax,ax
  1659.     jz    swxms_error
  1660.     mov    ax,xmsctl.lenlo        ;e adjust destination addr
  1661.                     ;d Zieladresse adjustieren
  1662.     add    xmsctl.destlo,ax
  1663.     mov    ax,xmsctl.lenhi
  1664.     adc    xmsctl.desthi,ax
  1665. ;
  1666.     cmp    currdesc.num_follow,0    ;e another MCB?
  1667.                     ;d noch ein MCB?
  1668.     je    swxms_complete
  1669. ;
  1670.     mov    xmsctl.lenlo,TYPE mcbdesc
  1671.     mov    xmsctl.lenhi,0
  1672.     mov    xmsctl.srchi,ds
  1673.     mov    xmsctl.srclo,offset nextmcb
  1674.     mov    si,offset xmsctl
  1675.     mov    ah,0bh
  1676.     call    swap_prep.xmm        ; move it
  1677.     or    ax,ax
  1678.     jz    swxms_error
  1679.     add    xmsctl.destlo,16    ; one paragraph
  1680.     adc    xmsctl.desthi,0
  1681. ;
  1682. swxms_complete:
  1683.     xor    ax,ax
  1684.     ret
  1685. ;
  1686. swxms_error:
  1687.     mov    ah,0ah            ;e release XMS frame on error
  1688.                     ;d Bei Fehler XMS-Speicher freigeben
  1689.     mov    dx,swap_prep.handle    ; XMS handle
  1690.     call    swap_prep.xmm
  1691.     mov    ax,RC_SWAPERROR
  1692.     or    ax,ax
  1693.     ret
  1694. ;
  1695. swapout_xms    endp
  1696. ;
  1697. ;>e
  1698. ;    swapout_file:    swap out an MCB block to file.
  1699. ;
  1700. ;    Entry:    "currdesc"     contains description of block to swap
  1701. ;        "nextmcb"    contains MCB-descriptor of next block
  1702. ;                if currdesc.num_follow is nonzero
  1703. ;
  1704. ;    Exit:    0 if OK, -1 if error, Zero-flag set accordingly.
  1705. ;
  1706. ;    Uses:    All regs excpt DS
  1707. ;<
  1708. ;>d
  1709. ;    swapout_file:    Auslagern eines MCB auf Datei.
  1710. ;
  1711. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1712. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1713. ;                wenn currdesc.num_follow nicht 0 ist.
  1714. ;
  1715. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1716. ;
  1717. ;    Benutzt: Alle Register außer DS
  1718. ;<
  1719. swapout_file    proc    near
  1720. ;
  1721.     push    ds
  1722.     mov    cx,currdesc.swsize    ;e size in paragraphs
  1723.                     ;d Blocklänge in Paragraphen
  1724.     mov    bx,swap_prep.handle    ; file handle
  1725.     mov    dx,currdesc.swoffset    ; swap offset
  1726.     mov    ds,currdesc.addr    ; segment to swap
  1727. ;
  1728. swfile_loop:
  1729.     mov    ax,cx
  1730.     cmp    ah,8h            ;e above 32k?
  1731.                     ;d mehr als 32k?
  1732.     jbe    swfile_ok        ;e go write if not
  1733.                     ;d schreiben wenn nein
  1734.     mov    ax,800h            ;e else write 32k
  1735.                     ;d sonst 32k schreiben
  1736. ;
  1737. swfile_ok:
  1738.     sub    cx,ax            ;e remaining length
  1739.                     ;d Restlänge
  1740.     push    cx            ;e save it
  1741.                     ;d sichern
  1742.     push    ax            ;e and save paras to write
  1743.                     ;d Sichern Länge in Paragraphen
  1744.     mov    cl,4
  1745.     shl    ax,cl            ;e convert to bytes
  1746.                     ;d Konvertieren in Anzahl Bytes
  1747.     mov    cx,ax
  1748.     mov    ah,40h            ; write
  1749.     int    21h
  1750.     jc    swfile_error
  1751.     cmp    ax,cx
  1752.     jne    swfile_error
  1753.     pop    cx            ;e paras written
  1754.                     ;d Geschriebene Paragraphen
  1755.     mov    ax,ds
  1756.     add    ax,cx            ;e bump up source segment
  1757.                     ;d Add. Kopierlänge auf Quellsegment
  1758.     mov    ds,ax
  1759.     pop    cx            ;e remaining length
  1760.                     ;d Restlänge
  1761.     or    cx,cx            ;e anything left?
  1762.                     ;d Noch etwas übrig?
  1763.     jnz    swfile_loop        ;e go loop if yes
  1764.                     ;d Nochmal wenn ja
  1765. ;
  1766.     pop    ds
  1767.     cmp    currdesc.num_follow,0    ;e another MCB?
  1768.                     ;d noch ein MCB?
  1769.     je    swfile_complete        ;e ready if not
  1770.                     ;d Fertig wenn nein
  1771.     mov    cx,16            ;e write one paragraph
  1772.                     ;d einen Paragraphen schreiben
  1773.     mov    dx,offset nextmcb
  1774.     mov    ah,40h
  1775.     int    21h
  1776.     jc    swfile_error1
  1777.     cmp    ax,cx
  1778.     jne    swfile_error1
  1779. ;
  1780. swfile_complete:
  1781.     xor    ax,ax
  1782.     ret
  1783. ;
  1784. swfile_error:
  1785.     pop    cx
  1786.     pop    cx
  1787.     pop    ds
  1788. swfile_error1:
  1789.     mov    ah,3eh            ; close file
  1790.     int    21h
  1791.     mov    dx,offset swap_prep.swapfilename
  1792.     mov    ah,41h            ; delete file
  1793.     int    21h
  1794.     mov    ax,RC_SWAPERROR
  1795.     or    ax,ax
  1796.     ret
  1797. ;
  1798. swapout_file    endp
  1799. ;
  1800. ;--------------------------------------------------------------------------
  1801. ;
  1802.     IF    REDIRECT
  1803. ;>e
  1804. ;    @redirect: Redirect a file.
  1805. ;
  1806. ;    Entry:    DS:SI = Filename pointer
  1807. ;        AX zero if filename is NULL
  1808. ;        CX    = Handle to redirect
  1809. ;        ES:DI = Handle save pointer
  1810. ;
  1811. ;    Exit:    Carry set on error, then AL has DOS error code
  1812. ;        ES:DI updated
  1813. ;
  1814. ;    Uses:    AX,BX,DX,SI
  1815. ;<
  1816. ;>d
  1817. ;    @redirect: Umleiten einer Datei.
  1818. ;
  1819. ;    Entry:    DS:SI = Zeiger auf Dateinamen
  1820. ;        AX ist 0 wenn Dateinamenszeiger NULL ist
  1821. ;        CX    = Umzuleitendes Handle
  1822. ;        ES:DI = Zeiger auf Handle-Sicherungswort
  1823. ;
  1824. ;    Exit:    Carry gesetzt bei Fehler, dann ist AL=DOS-Fehlercode
  1825. ;        ES:DI wird modifiziert.
  1826. ;
  1827. ;    Uses:    AX,BX,DX,SI
  1828. ;<
  1829. @redirect    proc    near
  1830.         local    doserr
  1831. ;
  1832.     or    ax,ax
  1833.     jz    no_redirect
  1834.     cmp    byte ptr [si],0
  1835.     jne    do_redirect
  1836. ;
  1837. no_redirect:
  1838.     mov    ax,-1
  1839.     stosw
  1840.     ret
  1841. ;
  1842. do_redirect:
  1843.     IFDEF    PASCAL
  1844.     inc    si            ;e skip length byte
  1845.                     ;d Längenbyte überspringen
  1846.     ENDIF
  1847.     or    cx,cx
  1848.     jnz    redir_write
  1849.     mov    dx,si
  1850.     mov    ax,3d00h    ; open file, read only
  1851.     int    21h
  1852.     mov    doserr,ax
  1853.     jc    redir_failed
  1854. ;
  1855. redir_ok:
  1856.     mov    dx,ax
  1857.     mov    ah,45h        ; duplicate handle
  1858.     mov    bx,cx
  1859.     int    21h
  1860.     mov    doserr,ax
  1861.     jc    redir_failed_dup
  1862.     push    ax
  1863.     mov    bx,dx
  1864.     mov    ah,46h        ; force duplicate handle
  1865.     int    21h
  1866.     mov    doserr,ax
  1867.     pop    ax
  1868.     jc    redir_failed_force
  1869.     stosw
  1870.     mov    ah,3eh        ; close file
  1871.     int    21h
  1872.     clc
  1873.     ret
  1874. ;
  1875. redir_failed_force:
  1876.     mov    bx,ax
  1877.     mov    ah,3eh        ; close file
  1878.     int    21h
  1879. ;
  1880. redir_failed_dup:
  1881.     mov    bx,dx
  1882.     mov    ah,3eh        ; close file
  1883.     int    21h
  1884. ;
  1885. redir_failed:
  1886.     mov    ax,doserr
  1887.     stc
  1888.     ret
  1889. ;
  1890. redir_write:
  1891.     cmp    byte ptr [si],'>'
  1892.     jne    no_append
  1893.     inc    si
  1894.     mov    dx,si
  1895.     mov    ax,3d02h        ; open file, read/write
  1896.     int    21h
  1897.     jc    no_append
  1898.     mov    bx,ax
  1899.     push    cx
  1900.     mov    ax,4202h        ; move file, offset from EOF
  1901.     xor    cx,cx
  1902.     mov    dx,cx
  1903.     int    21h
  1904.     mov    doserr,ax
  1905.     pop    cx
  1906.     mov    ax,bx
  1907.     jnc    redir_ok
  1908.     mov    dx,ax
  1909.     jmp    redir_failed_dup
  1910. ;
  1911. no_append:
  1912.     mov    dx,si
  1913.     mov    ah,3ch
  1914.     push    cx
  1915.     xor    cx,cx
  1916.     int    21h
  1917.     mov    doserr,ax
  1918.     pop    cx
  1919.     jc    redir_failed
  1920.     jmp    redir_ok
  1921. ;
  1922. @redirect    endp
  1923. ;
  1924.     ENDIF
  1925. ;
  1926. ;--------------------------------------------------------------------------
  1927. ;
  1928.     IFDEF    PASCAL
  1929.     IF    PAS_FREE
  1930. ;
  1931. ;e    @freepas: Chain unused Pascal Heap into DOS free list.
  1932. ;d    @freepas: Den unbenutzten Pascal Heap in die DOS Freiliste einfügen.
  1933. ;
  1934. @freepas    proc    near
  1935. ;
  1936.     mov    swap_prep.pmemid,0    ;e Init to no free block
  1937.                     ;d Init auf keinen freien Block
  1938. ;>e
  1939. ;    Load pointer to end of unused heap. For TP 5.x, this is
  1940. ;    FreePtr (which has to be adjusted if the offset part is 0).
  1941. ;    For TP 6.x, it is HeapEnd.
  1942. ;    For both versions, there may be data located after this
  1943. ;    pointer, so we may have to create an MCB.
  1944. ;<
  1945. ;>d
  1946. ;    Zeiger auf Ende des unbenutzten Heap laden. Für TP 5.x, der Zeiger
  1947. ;    ist FreePtr (muß adjustiert werden wenn der Offset-Teil 0 ist).
  1948. ;    Für TP 6.x ist es HeapEnd.
  1949. ;    Für beide Versionen können nach diesem Zeiger noch Daten folgen,
  1950. ;    sodaß eventuell ein MCB erzeugt werden muß.
  1951. ;<
  1952.     IF    TPAS_6
  1953.     mov    ax,word ptr HeapEnd
  1954.     mov    dx,word ptr HeapEnd+2
  1955.     ELSE
  1956.     mov    ax,word ptr FreePtr
  1957.     mov    dx,word ptr FreePtr+2
  1958.     or    ax,ax            ; offset 0?
  1959.     jnz    freepok
  1960.     add    dx,1000h        ; adjust segment
  1961. freepok:
  1962.     ENDIF
  1963.     mov    cl,4
  1964.     shr    ax,cl
  1965.     add    ax,dx        ;e FreeList/HeapEnd segment (rounded down)
  1966.                 ;d Segment von Freiliste/HeapEnd (abgerundet)
  1967.     dec    ax        ; MCB addr FreeList/HeapEnd segment
  1968.     mov    si,ax
  1969. ;
  1970.     mov    bx,word ptr HeapPtr
  1971.     mov    dx,word ptr HeapPtr+2
  1972.     add    bx,0fh
  1973.     shr    bx,cl
  1974.     add    bx,dx        ; heap end segment (rounded up)
  1975.     mov    di,bx
  1976. ;
  1977.     sub    ax,bx        ; free heap size
  1978.     jc    pnofree
  1979.     cmp    ax,1024        ;e don't bother if less than 16k
  1980.                 ;d nicht freigeben wenn weniger als 16k
  1981.     jbe    pnofree
  1982. ;
  1983.     mov    ax,PrefixSeg    ; PSP
  1984.     sub    bx,ax        ; size of space in use
  1985.     dec    ax        ; MCB
  1986.     mov    es,ax
  1987.     inc    ax
  1988. ;
  1989. ;e    Modify base MCB to contain only the part up to HeapPtr.
  1990. ;d    Den Basis-MCB modifizieren, daß er nur den Teil bis HeapPtr enthält.
  1991. ;
  1992.     mov    cl,es:id    ; save MCB ID
  1993.     mov    swap_prep.pmemid,cl
  1994.     mov    es:id,'M'
  1995.     mov    dx,es:paras
  1996.     mov    swap_prep.pmempar,dx
  1997.     mov    es:paras,bx
  1998. ;
  1999. ;e    Insert new, free, MCB at address HeapPtr.
  2000. ;d    Neuen, als frei markierten, MCB an Adresse HeapPtr einfügen.
  2001. ;
  2002.     mov    es,di        ; HeapPtr
  2003.     sub    dx,bx
  2004.     dec    dx
  2005.     mov    es:id,'M'
  2006.     mov    es:owner,0
  2007.     mov    bx,si        ; HeapEnd/FreeList
  2008.     sub    bx,di        ; - HeapPtr
  2009.     dec    bx        ; - 1 (MCB)
  2010.     mov    es:paras,bx
  2011. ;
  2012.     sub    dx,bx
  2013.     dec    dx
  2014.     jnz    frnotempty
  2015.     inc    es:paras
  2016.     mov    es:id,cl
  2017.     jmp    short pnofree
  2018. ;>e
  2019. ;    There is a non-empty block after HeapEnd/FreePtr. Insert an MCB
  2020. ;    with Owner = PSP.
  2021. ;<
  2022. ;>d
  2023. ;    Es existiert ein nicht leerer Block nach HeapEnd/FreePtr. Einen
  2024. ;    MCB mit Owner = PSP erzeugen.
  2025. ;<
  2026. frnotempty:
  2027.     mov    es,si        ; HeapEnd/FreeList
  2028.     mov    es:id,cl
  2029.     mov    es:owner,ax
  2030.     mov    es:paras,dx
  2031. ;
  2032. pnofree:
  2033.     ret
  2034. ;
  2035. @freepas    endp
  2036. ;>e
  2037. ;    @restpas - restore original memory layout modified by @freepas
  2038. ;<    
  2039. ;>d
  2040. ;    @restpas - von @freepas modifiziertes Original-Speicher-Layout 
  2041. ;           wiederherstellen
  2042. ;<    
  2043. @restpas    proc    near
  2044. ;
  2045.     mov    al,swap_prep.pmemid
  2046.     or    al,al
  2047.     jz    norestpas
  2048.     mov    bx,PrefixSeg
  2049.     dec    bx
  2050.     mov    es,bx
  2051.     mov    es:id,al
  2052.     mov    ax,swap_prep.pmempar
  2053.     mov    es:paras,ax
  2054. ;
  2055. norestpas:
  2056.     ret
  2057. ;
  2058. @restpas    endp
  2059.     ENDIF
  2060.     ENDIF
  2061. ;
  2062. ;--------------------------------------------------------------------------
  2063. ;--------------------------------------------------------------------------
  2064. ;
  2065. ;
  2066.     IFDEF    PASCAL
  2067.     IFDEF    FARCALL
  2068. do_spawn    PROC    far swapping: word, execfname: dword, params: dword, envlen: word, envp: dword, stdin: dword, stdout: dword, stderr: dword
  2069.     ELSE
  2070. do_spawn    PROC    near swapping: word, execfname: dword, params: dword, envlen: word, envp: dword, stdin: dword, stdout: dword, stderr: dword
  2071.     ENDIF
  2072.     ELSE
  2073. do_spawn    PROC    uses si di,swapping: word, execfname:ptr byte,params:ptr byte,envlen:word,envp:ptr byte,stdin:ptr byte, stdout:ptr byte, stderr:ptr byte
  2074.     ENDIF
  2075.     local    datseg,pspseg,currmcb,dos33
  2076. ;
  2077.     IFDEF    TC_HUGE
  2078.     mov    ax,SEG my_data
  2079.     mov    ds,ax
  2080.     ENDIF
  2081. ;
  2082.     mov    datseg,ds        ;e save default DS
  2083.                     ;d Default-DS sichern
  2084. ;
  2085.     mov    dos33,0
  2086.     mov    ax,3000h        ; get DOS version
  2087.     int    21h
  2088.     cmp    al,3
  2089.     jb    notdos33
  2090.     ja    isdos33
  2091.     cmp    ah,33
  2092.     jb    notdos33
  2093. isdos33:
  2094.     mov    dos33,1
  2095. notdos33:
  2096. ;
  2097.     IFDEF    PASCAL
  2098.     cld
  2099.     mov    bx,prefixseg
  2100.     ELSE
  2101.     IFDEF    TC_HUGE
  2102.     mov    ax,SEG _psp
  2103.     mov    es,ax
  2104.     mov    bx,es:_psp
  2105.     ELSE
  2106.     mov    bx,_psp
  2107.     ENDIF
  2108.     ENDIF
  2109.     mov    pspseg,bx
  2110. ;
  2111. ;e    Check if spawn is too low in memory
  2112. ;d    Prüfen ob dieses Modul zu weit unten im Speicher liegt
  2113. ;
  2114.     mov    ax,cs
  2115.     mov    dx,offset lowcode_begin
  2116.     mov    cl,4
  2117.     shr    dx,cl
  2118.     add    ax,dx            ;e normalized start of this code
  2119.                     ;d Normalisierter Beginn des Codes
  2120.     mov    dx,keep_paras        ;e the end of the modified area
  2121.                     ;d Ende des modifizierten Bereichs
  2122.     add    dx,bx            ;e plus PSP = end paragraph
  2123.                     ;d plus PSP = letzer Paragraph
  2124.     cmp    ax,dx
  2125.     ja    doswap_ok    ;e ok if start of code > end of low mem
  2126.                 ;d OK wenn Code-Beginn > Ende residenter Teil
  2127.     mov    ax,RC_TOOLOW
  2128.     ret
  2129. ;
  2130. doswap_ok:
  2131.     cmp    swapping,0
  2132.     jle    method_ok
  2133. ;
  2134. ;e    check the swap method, to make sure prep_swap has been called
  2135. ;d    Prüfen Auslagerungsmethode um sicherzustellen daß prep_swap
  2136. ;d    aufgerufen wurde.
  2137. ;
  2138.     mov    al,swap_prep.swapmethod
  2139.     cmp    al,USE_EMS
  2140.     je    method_ok
  2141.     cmp    al,USE_XMS
  2142.     je    method_ok
  2143.     cmp    al,USE_FILE
  2144.     je    method_ok
  2145.     mov    ax,RC_BADPREP
  2146.     ret
  2147. ;>e
  2148. ;    Save the memory below the swap space.
  2149. ;    We must do this before swapping, so the saved memory is
  2150. ;    in the swapped out image.
  2151. ;    Anything else we'd want to save on the stack or anywhere
  2152. ;    else in "normal" memory also has to be saved here, any
  2153. ;    modifications done to memory after the swap will be lost.
  2154. ;
  2155. ;    Note that the memory save is done even when not swapping,
  2156. ;    because we use some of the variables in low core for
  2157. ;    simplicity.
  2158. ;<
  2159. ;>d
  2160. ;    Sichern des Speichers unterhalb des Auslagerungsbereichs.
  2161. ;    Dies muß vor dem Auslagern geschehen damit der gesicherte
  2162. ;    Bereich mit im Ausgelagerten Abbild ist.
  2163. ;    Auch alles Andere das auf dem Stack oder sonst im "normalen"
  2164. ;    Speicher gesichert werden soll muß hier gesichert werden,
  2165. ;    da alle Modifikationen des Speichers die nach dem Auslagern
  2166. ;    erfolgen verloren gehen.
  2167. ;
  2168. ;    Das Sichern des Speichers ist auch notwendig wenn keine Auslagerung
  2169. ;    stattfindet, da Teile des sonst residenten Bereichs im unteren
  2170. ;    Speicher in jedem Fall verwendet werden.
  2171. ;<
  2172. method_ok:
  2173.     mov    es,datseg
  2174.     mov    ds,pspseg        ;e DS points to PSP
  2175.                     ;d DS zeigt auf PSP
  2176.     mov    si,5ch
  2177.     mov    di,offset save_dat
  2178.     mov    cx,savespace / 2    ;e NOTE: savespace is always even
  2179.                     ;d HINWEIS: savespace ist stets gerade
  2180.     rep movsw
  2181. ;
  2182.     mov    ds,datseg
  2183.     IFDEF    PASCAL
  2184.     IF    PAS_FREE
  2185.     call    @freepas
  2186.     ENDIF
  2187.     ENDIF
  2188. ;
  2189.     mov    ax,swapping
  2190.     cmp    ax,0
  2191.     jg    begin_swap
  2192. ;>e
  2193. ;    not swapping, prep_swap wasn't called. Init those variables in
  2194. ;      the 'swap_prep' block we need in any case.
  2195. ;<
  2196. ;>d
  2197. ;    Keine Auslagerung, prep_swap wurde nicht aufgerufen. Die Variablen
  2198. ;    im 'swap_prep'-Block initialisieren die in jedem Fall gebraucht werden.
  2199. ;<
  2200.     mov    swap_prep.swapmethod,al
  2201.     je    no_reduce
  2202. ;
  2203.     mov    ax,pspseg
  2204.     dec    ax
  2205.     mov    swap_prep.psp_mcb,ax
  2206.     mov    swap_prep.first_mcb,ax
  2207.     inc    ax
  2208.     mov    es,ax
  2209.     mov    bx,es:psp_envptr
  2210.     mov    swap_prep.env_mcb,bx
  2211.     mov    swap_prep.noswap_mcb,0
  2212.     cmp    envlen,0
  2213.     jne    swp_can_swap_env
  2214.     mov    swap_prep.noswap_mcb,bx
  2215. ;
  2216. swp_can_swap_env:
  2217.     IF    NOT NO_INHERIT
  2218.     mov    swap_prep.noswap_mcb2,0
  2219.     cmp    dos33,0
  2220.     je    swp_no_exthandle
  2221.     mov    ax,es:psp_handleptrs
  2222.     mov    bx,es
  2223.     cmp    ax,bx
  2224.     je    swp_no_exthandle
  2225.     dec    ax
  2226.     mov    swap_prep.noswap_mcb2,ax
  2227. ;
  2228. swp_no_exthandle:
  2229.     ENDIF
  2230.     xor    bx,bx
  2231.     mov    es,bx
  2232.     mov    ah,52h            ; get list of lists
  2233.     int    21h
  2234.     mov    ax,es
  2235.     or    ax,bx
  2236.     jz    no_reduce
  2237.     mov    es,es:[bx-2]        ; first MCB
  2238.     cmp    es:id,4dh        ; normal ID?
  2239.     jne    no_reduce
  2240.     mov    swap_prep.first_mcb,es
  2241. ;
  2242. no_reduce:
  2243.     jmp    no_swap1
  2244. ;
  2245. ;e    set up first block descriptor
  2246. ;d    Ersten Block-Deskriptor aufsetzen
  2247. ;
  2248. begin_swap:
  2249.     mov    ax,swap_prep.first_mcb
  2250.     mov    currmcb,ax
  2251.     mov    es,swap_prep.psp_mcb    ;e let ES point to base MCB
  2252.                     ;d ES zeigt auf Basis-MCB
  2253.     mov    ax,es:paras
  2254.     mov    currdesc.msize,ax
  2255.     sub    ax,keep_paras
  2256.     mov    currdesc.swsize,ax
  2257.     mov    currdesc.addr,es
  2258.     mov    currdesc.swoffset,swapbeg + 16
  2259. ;e        NOTE: swapbeg is 1 para higher when seen from MCB
  2260. ;d        HINWEIS: swapbeg ist 1 Paragraph höher vom MCB aus gesehen
  2261.     mov    ax,swap_prep.total_mcbs
  2262.     mov    currdesc.num_follow,ax
  2263. ;
  2264. ;e    init other vars
  2265. ;d    andere Variablen initialisieren
  2266. ;
  2267.     mov    xmsctl.destlo,0
  2268.     mov    xmsctl.desthi,0
  2269.     mov    ems_curpage,0
  2270.     mov    ems_curoff,ems_parasize
  2271. ;>e
  2272. ;    Do the swapping. Each MCB block (except the last) has an 
  2273. ;    "mcbdesc" structure appended that gives location and size 
  2274. ;    of the next MCB.
  2275. ;<
  2276. ;>d
  2277. ;    Auslagerung ausführen. An jeden MCB-Block (außer den letzten)
  2278. ;    wird eine "mcbdesc" Struktur zur Beschreibung von Adresse und
  2279. ;    Größe des nächsten Blocks angefügt.
  2280. ;<
  2281. swapout_main:
  2282.     cmp    currdesc.num_follow,0    ;e next block?
  2283.                     ;d Gibt es einen nächsten?
  2284.     je    swapout_no_next        ;e ok if not
  2285.                     ;d OK wenn nein
  2286. ;>e
  2287. ;    There is another MCB block to be saved. So we don't have
  2288. ;    to do two calls to the save routine with complicated
  2289. ;    parameters, we set up the next MCB descriptor beforehand.
  2290. ;    Walk the MCB chain starting at the current MCB to find
  2291. ;    the next one belonging to this process.
  2292. ;<
  2293. ;>d
  2294. ;    Es gibt einen weiteren auszulagernden MCB-Block. Um die 
  2295. ;    Auslagerungsroutine nicht getrennt für den MCB-Deskriptor
  2296. ;    aufrufen zu müssen (mit einer entsprechend aufwendigeren
  2297. ;    Parameterversorgung), wird der Deskriptor für den Folgeblock
  2298. ;    vor Aufruf erstellt.
  2299. ;    Dazu muß die MCB-Kette, beginnend beim derzeitigen Block,
  2300. ;    durchgegangen werden um den nächsten zum Prozeß gehörenden
  2301. ;    Block zu finden.
  2302. ;<
  2303.     mov    ax,currmcb
  2304.     mov    bx,pspseg
  2305.     mov    cx,swap_prep.psp_mcb
  2306.     mov    dx,swap_prep.noswap_mcb
  2307. ;
  2308. swm_mcb_walk:
  2309.     mov    es,ax
  2310.     cmp    ax,cx
  2311.     je    swm_next_mcb
  2312.     cmp    ax,dx
  2313.     je    swm_next_mcb
  2314.     IF    NOT NO_INHERIT
  2315.     cmp    ax,swap_prep.noswap_mcb2
  2316.     je    swm_next_mcb
  2317.     ENDIF
  2318. ;
  2319.     cmp    bx,es:owner        ;e our process?
  2320.                     ;d Dieser Prozeß?
  2321.     je    swm_mcb_found        ;e found it if yes
  2322.                     ;d gefunden wenn ja
  2323. ;
  2324. swm_next_mcb:
  2325.     cmp    es:id,4dh        ;e normal block?
  2326.                     ;d Normaler Block?
  2327.     jne    swm_mcb_error        ;e error if end of chain
  2328.                     ;d Fehler wenn Ende der Kette
  2329.     add    ax,es:paras        ; start + length
  2330.     inc    ax            ; next MCB
  2331.     jmp    swm_mcb_walk
  2332. ;
  2333. ;e    MCB found, set up an mcbdesc in the "nextmcb" structure
  2334. ;d    MCB gefunden, aufsetzen mcbdesc in der "nextmcb" Struktur
  2335. ;
  2336. swm_mcb_found:
  2337.     mov    nextmcb.addr,es
  2338.     mov    ax,es:paras        ;e get number of paragraphs
  2339.                     ;d Anzahl Paragraphen
  2340.     mov    nextmcb.msize,ax    ;e and save
  2341.                     ;d sichern
  2342.     inc    ax
  2343.     mov    nextmcb.swsize,ax
  2344.     mov    bx,es
  2345.     add    bx,ax
  2346.     mov    currmcb,bx
  2347.     mov    nextmcb.swoffset,0
  2348.     mov    ax,currdesc.num_follow
  2349.     dec    ax
  2350.     mov    nextmcb.num_follow,ax
  2351. ;
  2352. swapout_no_next:
  2353.     cmp    swap_prep.swapmethod,USE_EMS
  2354.     je    swm_ems
  2355.     cmp    swap_prep.swapmethod,USE_XMS
  2356.     je    swm_xms
  2357.     call    swapout_file
  2358.     jmp    short swm_next
  2359. ;
  2360. swm_ems:
  2361.     call    swapout_ems
  2362.     jmp    short swm_next
  2363. ;
  2364. swm_xms:
  2365.     call    swapout_xms
  2366. ;
  2367. swm_next:
  2368.     jnz    swapout_error
  2369.     cmp    currdesc.num_follow,0
  2370.     je    swapout_complete
  2371. ;>e
  2372. ;    next MCB exists, copy the "nextmcb" descriptor into
  2373. ;    currdesc, and loop.
  2374. ;<
  2375. ;>d
  2376. ;    Es gibt einen Folgeblock, der "nextmcb" Deskriptor wird in den
  2377. ;    "currdesc" Deskriptor kopiert, und das ganze noch mal von vorn.
  2378. ;<
  2379.     mov    es,datseg
  2380.     mov    si,offset nextmcb
  2381.     mov    di,offset currdesc
  2382.     mov    cx,TYPE mcbdesc
  2383.     rep movsb
  2384.     jmp    swapout_main
  2385. ;
  2386. ;
  2387. swm_mcb_error:
  2388.     mov    ax,RC_MCBERROR
  2389. ;
  2390. swapout_kill:
  2391.     cmp    swapping,0
  2392.     jl    swapout_error
  2393.     push    ax
  2394.     cmp    swap_prep.swapmethod,USE_FILE
  2395.     je    swm_mcberr_file
  2396.     cmp    swap_prep.swapmethod,USE_EMS
  2397.     je    swm_mcberr_ems
  2398. ;
  2399.     mov    ah,0ah            ;e release XMS frame on error
  2400.                     ;d Bei Fehler XMS-Block freigeben
  2401.     mov    dx,swap_prep.handle    ; XMS handle
  2402.     call    swap_prep.xmm
  2403.     pop    ax
  2404.     jmp    short swapout_error
  2405. ;
  2406. swm_mcberr_ems:
  2407.     mov    dx,swap_prep.handle    ; EMS handle
  2408.     mov    ah,45h            ;e release EMS pages on error
  2409.                     ;d Bei Fehler EMS freigeben
  2410.     int    EMM_INT
  2411.     pop    ax
  2412.     jmp    short swapout_error
  2413. ;
  2414. swm_mcberr_file:
  2415.     mov    bx,swap_prep.handle
  2416.     cmp    bx,-1
  2417.     je    swm_noclose
  2418.     mov    ah,3eh            ; close file
  2419.     int    21h
  2420. swm_noclose:
  2421.     mov    dx,offset swap_prep.swapfilename
  2422.     mov    ah,41h            ; delete file
  2423.     int    21h
  2424.     pop    ax
  2425. ;
  2426. swapout_error:
  2427.     IFDEF    PASCAL
  2428.     IF    PAS_FREE
  2429.     call    @restpas
  2430.     ENDIF
  2431.     ENDIF
  2432.     ret
  2433. ;
  2434. ;>e
  2435. ;    Swapout complete. Close the handle (EMS/file only),
  2436. ;    then set up low memory.
  2437. ;<
  2438. ;>d
  2439. ;    Auslagerung abgeschlossen. Die Datei bzw. die EMS-Seite wird
  2440. ;    geschlossen, und der residente Bereich wird initialisiert.
  2441. ;<
  2442. swapout_complete:
  2443.     cmp    swap_prep.swapmethod,USE_FILE
  2444.     jne    swoc_nofile
  2445. ;
  2446. ;e    File swap: Close the swap file to make the handle available
  2447. ;d    Auslagerung auf Datei: Datei schließen um den Handle freizumachen
  2448. ;
  2449.     mov    bx,swap_prep.handle
  2450.     mov    swap_prep.handle,-1
  2451.     mov    ah,3eh
  2452.     int    21h            ; close file
  2453.     mov    si,offset swapin_file
  2454.     jnc    swoc_ready
  2455.     mov    ax,RC_SWAPERROR
  2456.     jmp    swapout_kill
  2457. ;
  2458. swoc_nofile:
  2459.     cmp    swap_prep.swapmethod,USE_EMS
  2460.     jne    swoc_xms
  2461. ;
  2462. ;e    EMS: Unmap page
  2463. ;d    EMS: Seite unzugänglich machen
  2464. ;
  2465.     mov    ax,4400h
  2466.     mov    bx,-1
  2467.     mov    dx,swap_prep.handle
  2468.     int    EMM_INT
  2469.     mov    si,offset swapin_ems
  2470.     jmp    short swoc_ready
  2471. ;
  2472. swoc_xms:
  2473.     mov    si,offset swapin_xms
  2474.     jmp    short swoc_ready
  2475. ;
  2476. no_swap1:
  2477.     mov    si,offset swapin_none
  2478. ;    
  2479. ;e    Copy the appropriate swap-in routine to low memory.
  2480. ;d    Kopieren der der Auslagerungsmethode entsprechenden Routine
  2481. ;d    in den residenten Teil.
  2482. ;
  2483. swoc_ready:
  2484.     mov    es,pspseg
  2485.     mov    cx,swap_codelen / 2
  2486.     mov    di,codebeg + base_length
  2487.     push    ds
  2488.     mov    ax,cs
  2489.     mov    ds,ax
  2490.     rep movsw
  2491. ;>e
  2492. ;    And while we're at it, copy the MCB allocation routine (which
  2493. ;    also includes the initial MCB release and exec call) down.
  2494. ;<
  2495. ;>d
  2496. ;    Außerdem die MCB-Allozierungsroutine und den EXEC-Aufruf
  2497. ;    nach unten kopieren.
  2498. ;<
  2499.     mov    cx,base_length / 2
  2500.     mov    di,param_len
  2501.     mov    si,offset lowcode_begin
  2502.     rep movsw
  2503. ;
  2504.     pop    ds
  2505.     mov    bx,es
  2506.     dec    bx
  2507.     mov    es,bx        ;e let ES point to base MCB
  2508.                 ;d ES zeigt jetzt auf den Basisblock
  2509. ;>e
  2510. ;    Again set up the base MCB descriptor, and copy it as well as
  2511. ;    the variables set up by prep_swap to low memory.
  2512. ;    This isn't too useful if we're not swapping, but it doesn't
  2513. ;    hurt, either. The only variable used when not swapping is
  2514. ;    lprep.swapmethod.
  2515. ;<
  2516. ;>d
  2517. ;    Der Deskriptor für den Basisblock wird erneut aufgesetzt und,
  2518. ;    zusammen mit dem Variablenblock der durch prep_swap initialisiert
  2519. ;    wurde, nach unten kopieren.
  2520. ;    Wenn gar nicht ausgelagert wird, ist dies eigentlich nicht nicht
  2521. ;    notwendig, es schadet aber auch nicht. Die einzige Variable
  2522. ;    die in diesem Fall benötigt wird ist lprep.swapmethod.
  2523. ;<
  2524.     mov    ax,es:paras
  2525.     mov    currdesc.msize,ax
  2526.     sub    ax,keep_paras
  2527.     mov    currdesc.swsize,ax
  2528.     mov    currdesc.addr,es
  2529.     mov    currdesc.swoffset,swapbeg + 16
  2530.     mov    ax,swap_prep.total_mcbs
  2531.     mov    currdesc.num_follow,ax
  2532. ;
  2533.     mov    es,pspseg        ;e ES points to PSP again
  2534.                     ;d ES zeigt wieder auf PSP
  2535. ;
  2536.     mov    cx,TYPE prep_block
  2537.     mov    si,offset swap_prep
  2538.     mov    di,lprep
  2539.     rep movsb
  2540.     mov    cx,TYPE mcbdesc
  2541.     mov    si,offset currdesc
  2542.     mov    di,lcurrdesc
  2543.     rep movsb
  2544. ;
  2545. ;e    now set up other variables in low core
  2546. ;d    Nun werden die weiteren Variablen im residenten Tail initialisiert.
  2547. ;
  2548.     mov    ds,pspseg
  2549.     mov    ds:cgetmcb,getmcboff + codebeg
  2550.     mov    ds:eretcode,0
  2551.     mov    ds:retflags,0
  2552. ;
  2553. ;>e
  2554. ;    If 'NO_INHERIT' is nonzero, save the entries of the 
  2555. ;    handle table, and set the last 15 to 0ffh (unused).
  2556. ;<
  2557. ;>d
  2558. ;    Wenn 'NO_INHERIT' nicht 0 ist, Retten der Handle-Tabelle
  2559. ;    und Setzen der letzten 15 Einträge auf 0ffh (unbenutzt).
  2560. ;<
  2561.     IF    NO_INHERIT
  2562.     mov    si,psp_handletab
  2563.     mov    di,lhandlesave
  2564.     mov    cx,10
  2565.     rep movsw
  2566.     mov    si,psp_handlenum    ;e Length of handle table
  2567.                     ;d Länge Handle-Tabelle
  2568.     mov    ax,[si]
  2569.     stosw
  2570.     mov    word ptr [si],20    ;e set to default to be safe
  2571.                     ;d Auf Standardwert setzten
  2572.     add    si,2
  2573.     lodsw                ;e Handle table pointer
  2574.                     ;d Zeiger auf Handle-Tabelle
  2575.     mov    bx,ax
  2576.     stosw
  2577.     lodsw
  2578.     stosw
  2579.     cmp    dos33,0
  2580.     je    no_handlecopy
  2581.     cmp    ax,pspseg
  2582.     jne    copy_handles
  2583.     cmp    bx,psp_handletab
  2584.     je    no_handlecopy
  2585. ;>e
  2586. ;    if the handle table pointer in the PSP does not point to
  2587. ;    the default PSP location, copy the first five entries from
  2588. ;    this table into the PSP - but only if we have DOS >= 3.3.
  2589. ;<
  2590. ;>d
  2591. ;    Wenn der Handle-Tabellen-Pointer im PSP nicht auf den
  2592. ;    Standard-Platz im PSP zeigt, die ersten fünf Einträge
  2593. ;    aus dieser Tabelle in den PSP kopieren - aber nur bei
  2594. ;    einer DOS-Version >= 3.3.
  2595. ;<
  2596. copy_handles:
  2597.     mov    ds,ax
  2598.     mov    si,bx
  2599.     mov    di,psp_handletab
  2600.     mov    es:psp_handleptro,di
  2601.     mov    es:psp_handleptrs,es
  2602.     movsw
  2603.     movsw
  2604.     movsb
  2605. ;
  2606. no_handlecopy:
  2607.     mov    di,psp_handletab+5
  2608.     mov    ax,0ffffh
  2609.     stosb
  2610.     mov    cx,7
  2611.     rep stosw
  2612. ;
  2613.     ENDIF
  2614. ;
  2615. ;e    Handle Redirection
  2616. ;d    Dateiumleitung behandeln
  2617. ;
  2618.     IF    REDIRECT
  2619.     mov    es,pspseg
  2620.     mov    di,lstdinsav
  2621.     mov    ax,-1
  2622.     stosw
  2623.     stosw
  2624.     stosw
  2625.     mov    di,lstdinsav
  2626.     xor    cx,cx
  2627.     IF    ptrsize
  2628.     lds    si,stdin
  2629.     mov    ax,ds
  2630.     or    ax,si
  2631.     ELSE
  2632.     mov    si,stdin
  2633.     mov    ds,datseg
  2634.     or    si,si
  2635.     ENDIF
  2636.     call    @redirect
  2637.     jc    failed_redir
  2638.     inc    cx
  2639.     IF    ptrsize
  2640.     lds    si,stdout
  2641.     mov    ax,ds
  2642.     or    ax,si
  2643.     ELSE
  2644.     mov    si,stdout
  2645.     or    si,si
  2646.     ENDIF
  2647.     call    @redirect
  2648.     jc    failed_redir
  2649.     inc    cx
  2650.     IF    ptrsize
  2651.     lds    si,stderr
  2652.     mov    ax,ds
  2653.     or    ax,si
  2654.     ELSE
  2655.     mov    si,stderr
  2656.     or    si,si
  2657.     ENDIF
  2658.     call    @redirect
  2659.     jnc    redir_complete
  2660. ;
  2661. failed_redir:
  2662.     push    ax
  2663. ;
  2664. ;e    restore handle table and pointer
  2665. ;d    Wiederherstellen Handle-Tabelle und Pointer
  2666. ;
  2667.     mov    ds,pspseg
  2668.     mov    si,lstdinsav
  2669.     xor    cx,cx
  2670. ;
  2671. redirclose:
  2672.     lodsw
  2673.     cmp    ax,-1
  2674.     je    redclosenext
  2675.     mov    bx,ax
  2676.     mov    ah,46h
  2677.     int    21h
  2678. ;
  2679. redclosenext:
  2680.     inc    cx
  2681.     cmp    cx,3
  2682.     jb    redirclose
  2683. ;
  2684.     IF    NO_INHERIT
  2685.     mov    ds,pspseg
  2686.     mov    es,pspseg
  2687.     mov    si,lhandlesave
  2688.     mov    di,psp_handletab
  2689.     mov    cx,10
  2690.     rep movsw
  2691.     mov    di,psp_handlenum
  2692.     movsw
  2693.     movsw
  2694.     movsw
  2695.     ENDIF
  2696. ;
  2697. ;e    Restore overwritten part of program
  2698. ;d    Den überschriebenen Teil des Programms wiederherstellen
  2699. ;
  2700.     mov    ds,datseg
  2701.     mov    es,pspseg
  2702.     mov    si,offset save_dat
  2703.     mov    di,5ch
  2704.     mov    cx,savespace
  2705.     rep movsb
  2706. ;
  2707.     pop    ax
  2708.     mov    ah,RC_REDIRFAIL SHR 8
  2709.     jmp    swapout_kill
  2710. ;
  2711. redir_complete:
  2712.     IF    NO_INHERIT
  2713.     mov    ds,pspseg
  2714.     mov    es,pspseg
  2715.     mov    si,psp_handletab+5
  2716.     mov    di,lredirsav
  2717.     mov    cx,3
  2718.     rep movsw
  2719.     mov    di,psp_handletab+5
  2720.     mov    cx,3
  2721.     mov    ax,0ffffh
  2722.     rep stosw
  2723.     ENDIF
  2724.     ENDIF
  2725. ;
  2726. ;e    Prepare exec parameter block
  2727. ;d    Parameterblock für EXEC-Aufruf vorbereiten
  2728. ;
  2729.     mov    ax,es
  2730.     mov    es:expar.fcb1seg,ax
  2731.     mov    es:expar.fcb2seg,ax
  2732.     mov    es:expar.pparseg,ax
  2733.     mov    es:expar.envseg,0
  2734. ;>e
  2735. ;    The 'zero' word is located at 80h in the PSP, the start of
  2736. ;    the command line. So as not to confuse MCB walking programs,
  2737. ;    a command line length of zero is inserted here.
  2738. ;<
  2739. ;>d
  2740. ;    Das 'zero'-Wort ist an Adresse 80h im PSP, dem Beginn der
  2741. ;    Kommandozeile. Um Programme die die MCB-Kette abarbeiten
  2742. ;    und dabei möglicherweise auf diese Kommandozeile zugreifen
  2743. ;    nicht zu verwirren, wird eine leere Kommandozeile eingefügt.
  2744. ;<
  2745.     mov    es:zero,0d00h        ;e 00h,0dh = empty command line
  2746.                     ;d 00h,0dh = Leere Kommandozeile
  2747. ;
  2748. ;e    Init default fcb's by parsing parameter string
  2749. ;d    Default FCB-Blöcke aus dem Parameter-String füllen
  2750. ;
  2751.     IF    ptrsize
  2752.     lds    si,params
  2753.     ELSE
  2754.     mov    si,params
  2755.     mov    ds,datseg
  2756.     ENDIF
  2757.     IFDEF    PASCAL
  2758.     inc    si            ;e skip length byte
  2759.                     ;d Längenbyte überspringen
  2760.     ENDIF
  2761.     push    si
  2762.     mov    di,xfcb1
  2763.     mov    es:expar.fcb1,di
  2764.     push    di
  2765.     mov    cx,16
  2766.     xor    ax,ax
  2767.     rep stosw            ;e init both fcb's to 0
  2768.                     ;d Beide FCBs mit 0 vorbesetzen
  2769.     pop    di
  2770.     mov    ax,2901h
  2771.     int    21h
  2772.     mov    di,xfcb2
  2773.     mov    es:expar.fcb2,di
  2774.     mov    ax,2901h
  2775.     int    21h
  2776.     pop    si
  2777. ;
  2778. ;e    move command tail string into low core
  2779. ;d    Kommandozeile in residenten Teil transferieren
  2780. ;
  2781.     mov    di,progpars
  2782.     mov    es:expar.ppar,di
  2783.     xor    cx,cx
  2784.     inc    di
  2785. cmdcpy:
  2786.     lodsb
  2787.     or    al,al
  2788.     jz    cmdcpy_end
  2789.     stosb
  2790.     inc    cx
  2791.     jmp    cmdcpy
  2792. ;
  2793. cmdcpy_end:
  2794.     mov    al,0dh
  2795.     stosb
  2796.     mov    es:progpars,cl
  2797. ;
  2798. ;e    move filename string into low core
  2799. ;d    Dateinamen in residenten Teil transferieren
  2800. ;
  2801.     IF    ptrsize
  2802.     lds    si,execfname
  2803.     ELSE
  2804.     mov    si,execfname
  2805.     ENDIF
  2806.     IFDEF    PASCAL
  2807.     inc    si
  2808.     ENDIF
  2809.     mov    di,filename
  2810. fncpy:
  2811.     lodsb
  2812.     stosb
  2813.     or    al,al
  2814.     jnz    fncpy
  2815. ;
  2816. ;e    Setup environment copy
  2817. ;d    Umgebungsvariablenblock-Kopie aufsetzen
  2818. ;
  2819.     mov    bx,keep_paras        ;e paras to keep
  2820.                     ;d Residente Paragraphen
  2821.     mov    cx,envlen        ;e environment size
  2822.                     ;d Größe Umgebungsvariablen
  2823.     jcxz    no_environ        ;e go jump if no environment
  2824.                     ;d Fertig wenn keine Umgebung
  2825.     cmp    swapping,0
  2826.     jne    do_envcopy
  2827. ;>e
  2828. ;    Not swapping, use the environment pointer directly.
  2829. ;    Note that the environment copy must be paragraph aligned.
  2830. ;<
  2831. ;>d
  2832. ;    Keine Auslagerung, der Umgebungs-Zeiger kann direkt verwendet
  2833. ;    werden. Dazu muß die Kopie der Umgebungsvariablen auf Paragraphen-
  2834. ;    Grenze adjustiert sein.
  2835. ;<
  2836.     IF    ptrsize
  2837.     mov    ax,word ptr (envp)+2
  2838.     mov    bx,word ptr (envp)
  2839.     ELSE
  2840.     mov    ax,ds
  2841.     mov    bx,envp
  2842.     ENDIF
  2843.     add    bx,15            ;e make sure it's paragraph aligned
  2844.                     ;d auf Paragraphengrenze bringen
  2845.     mov    cl,4
  2846.     shr    bx,cl            ;e and convert to segment addr
  2847.                     ;d in Segment-Adresse konvertieren
  2848.     add    ax,bx
  2849.     mov    es:expar.envseg,ax    ;e new environment segment
  2850.                     ;d Neues Umgebungs-Segment
  2851.     xor    cx,cx            ;e mark no copy
  2852.                     ;d Markieren daß keine Kopie nötig
  2853.     xor    bx,bx            ;e and no shrink
  2854.                     ;d und keine Speicherreduzierung
  2855.     jmp    short no_environ
  2856. ;>e
  2857. ;    Swapping or EXECing without return. Set up the pointers for
  2858. ;    an environment copy (we can't do the copy yet, it might overwrite
  2859. ;    this code).
  2860. ;<
  2861. ;>d
  2862. ;    Auslagerung, oder EXEC ohne Rückkehr. Die Zeiger für das
  2863. ;    kopieren der Umgebungsvariablen aufsetzen. Der Block darf
  2864. ;    jetzt noch nicht kopiert werden, da dies eventuell den gerade
  2865. ;    ausgeführten Code überschreiben könnte.
  2866. ;<
  2867. do_envcopy:
  2868.     inc    cx
  2869.     shr    cx,1            ;e words to copy
  2870.                     ;d Zu kopierende Worte
  2871.     mov    ax,cx            ;e convert envsize to paras
  2872.                     ;d in Paragraphen konvertieren
  2873.     add    ax,7
  2874.     shr    ax,1
  2875.     shr    ax,1
  2876.     shr    ax,1
  2877.     add    bx,ax            ;e add envsize to paras to keep
  2878.                     ;d Größe zu residenter addieren
  2879.     IF    ptrsize
  2880.     lds    si,envp
  2881.     ELSE
  2882.     mov    si,envp
  2883.     ENDIF
  2884. ;
  2885.     mov    ax,es            ;e low core segment
  2886.                     ;d Segmentadresse residenter Teil
  2887.     add    ax,keep_paras        ;e plus fixed paras
  2888.                     ;d plus residente Paragraphen
  2889.     mov    es:expar.envseg,ax    ;e = new environment segment
  2890.                     ;d = neues Umgebungs-Segment
  2891. ;
  2892. ;e    Save stack regs, switch to local stack
  2893. ;d    Sichern Stack-Register, Umschalten auf lokalen Stack
  2894. ;
  2895. no_environ:
  2896.     mov    es:save_ss,ss
  2897.     mov    es:save_sp,sp
  2898.     mov    ax,es
  2899.     cli
  2900.     mov    ss,ax
  2901.     mov    sp,mystack
  2902.     sti
  2903. ;
  2904.     push    cx            ; save env length
  2905.     push    si            ; save env pointer
  2906.     push    ds            ; save env segment
  2907. ;
  2908. ;e    save and patch INT0 (division by zero) vector
  2909. ;d    Sichern und überschreiben INT0 (division by zero) Vektor
  2910. ;
  2911.     xor    ax,ax
  2912.     mov    ds,ax
  2913.     mov    ax,word ptr ds:0
  2914.     mov    es:div0_off,ax
  2915.     mov    ax,word ptr ds:2
  2916.     mov    es:div0_seg,ax
  2917.     mov    word ptr ds:0,codebeg + iretoff
  2918.     mov    word ptr ds:2,es
  2919. ;
  2920.     pop    ds            ; pop environment segment
  2921.     pop    si            ; pop environment offset
  2922.     pop    cx            ; pop environment length
  2923.     mov    di,swapbeg        ;e environment destination
  2924.                     ;d Zieladresse Umgebungsblock
  2925. ;
  2926. ;e    Push return address on local stack
  2927. ;d    Rückkehradresse auf lokalen Stack bringen
  2928. ;
  2929.     push    cs            ;e push return segment
  2930.                     ;d Rückkehr-Segment pushen
  2931.     mov    ax,offset exec_cont
  2932.     push    ax            ;e push return offset
  2933.                     ;d Rückkehr-Offset pushen
  2934.     mov    es:spx,sp        ;e save stack pointer
  2935.                     ;d Stack-Zeiger sichern
  2936. ;
  2937. ;e    Goto low core code
  2938. ;d    In den residenten Teil springen
  2939. ;
  2940.     push    es            ;e push entry segment
  2941.                     ;d Einsprungssegment pushen
  2942.         mov    ax,codebeg + doexec_entry
  2943.         push    ax            ;e push entry offset
  2944.                     ;d Einsprungsoffset pushen
  2945. ;e    ret    far            ; can't use RET here because
  2946. ;d    ret    far            ; RET kann hier wegen der .model-
  2947.     db    0cbh            ;e of .model
  2948.                     ;d Direktive nicht verwendet werden
  2949. ;
  2950. ;----------------------------------------------------------------
  2951. ;>e
  2952. ;    Low core code will return to this location, with DS set to
  2953. ;    the PSP segment.
  2954. ;<
  2955. ;>d
  2956. ;    Der residente Teil kehrt hierher zurück, mit DS = PSP-Segment.
  2957. ;<
  2958. exec_cont:
  2959.     push    ds
  2960.     pop    es
  2961.     cli
  2962.     mov    ss,ds:save_ss        ;e reload stack
  2963.                     ;d Stack zurückladen
  2964.     mov    sp,ds:save_sp
  2965.     sti
  2966. ;
  2967. ;e    restore handle table and pointer
  2968. ;d    Wiederherstellen Handle-Tabelle und Pointer
  2969. ;
  2970.     IF    NO_INHERIT
  2971.     mov    si,lhandlesave
  2972.     mov    di,psp_handletab
  2973.     mov    cx,10
  2974.     rep movsw
  2975.     mov    di,psp_handlenum
  2976.     movsw
  2977.     movsw
  2978.     movsw
  2979.     ENDIF
  2980. ;
  2981. ;e    restore INT0 (division by zero) vector
  2982. ;d    INT0 (division by zero) Vektor wiederherstellen
  2983. ;
  2984.     xor    cx,cx
  2985.     mov    ds,cx
  2986.     mov    cx,es:div0_off
  2987.     mov    word ptr ds:0,cx
  2988.     mov    cx,es:div0_seg
  2989.     mov    word ptr ds:2,cx
  2990. ;
  2991.     mov    ds,datseg
  2992. ;
  2993.     IFDEF    PASCAL
  2994.     IF    PAS_FREE
  2995.     push    es
  2996.     call    @restpas
  2997.     pop    es
  2998.     ENDIF
  2999.     ENDIF
  3000. ;
  3001.     mov    ax,es:eretcode
  3002.     mov    bx,es:retflags
  3003. ;
  3004. ;e    Restore overwritten part of program
  3005. ;d    Den überschriebenen Teil des Programms wiederherstellen
  3006. ;
  3007.     mov    si,offset save_dat
  3008.     mov    di,5ch
  3009.     mov    cx,savespace
  3010.     rep movsb
  3011. ;
  3012.     test    bx,1            ;e carry set?
  3013.                     ;d Carry-Flag gesetzt?
  3014.     jnz    exec_fault        ;e return EXEC error code if fault
  3015.                     ;d EXEC Fehler-code liefern wenn ja
  3016.     mov    ah,4dh            ;e else get program return code
  3017.                     ;d Sonst Programm-Rückgabewert holen
  3018.     int    21h
  3019.     ret
  3020. ;
  3021. exec_fault:
  3022.     mov    ah,3            ;e return error as 03xx
  3023.                     ;d EXEC-Fehler als 03xx liefern
  3024.     ret
  3025. ;    
  3026. do_spawn    ENDP
  3027. ;
  3028. ;----------------------------------------------------------------------------
  3029. ;----------------------------------------------------------------------------
  3030. ;
  3031. emm_name    db    'EMMXXXX0'
  3032. ;>e
  3033. ;    prep_swap - prepare for swapping.
  3034. ;
  3035. ;    This routine checks all parameters necessary for swapping,
  3036. ;    and attempts to set up the swap-out area in EMS/XMS, or on file.
  3037. ;    In detail:
  3038. ;
  3039. ;         1) Check whether the do_spawn routine is located
  3040. ;        too low in memory, so it would get overwritten.
  3041. ;        If this is true, return an error code (-2).
  3042. ;
  3043. ;         2) Walk the memory control block chain, adding up the
  3044. ;        paragraphs in all blocks assigned to this process.
  3045. ;
  3046. ;         3) Check EMS (if the method parameter allows EMS):
  3047. ;        - is an EMS driver installed?
  3048. ;        - are sufficient EMS pages available?
  3049. ;        if all goes well, the EMS pages are allocated, and the
  3050. ;        routine returns success (1).
  3051. ;
  3052. ;         4) Check XMS (if the method parameter allows XMS):
  3053. ;        - is an XMS driver installed?
  3054. ;        - is a sufficient XMS block available?
  3055. ;        if all goes well, the XMS block is allocated, and the
  3056. ;        routine returns success (2).
  3057. ;
  3058. ;         5) Check file swap (if the method parameter allows it):
  3059. ;        - try to create the file
  3060. ;        - pre-allocate the file space needed by seeking to the end
  3061. ;          and writing a byte.
  3062. ;        If the file can be written, the routine returns success (4).
  3063. ;
  3064. ;         6) Return an error code (-1).
  3065. ;<
  3066. ;>d
  3067. ;    prep_swap - Auslagerung vorbereiten.
  3068. ;
  3069. ;    Diese Routine prüft die zur Auslagerung nötigen Parameter,
  3070. ;    und versucht den Auslagerungsbereich in EMS, XMS, oder auf Datei,
  3071. ;    vorzubereiten.
  3072. ;    Im einzelnen:
  3073. ;
  3074. ;         1) Prüfen ob die do_spawn-Routine so niedrig liegt daß
  3075. ;        sie durch die Auslagerung überschrieben würde.
  3076. ;        Ist dies der Fall, Fehler (-2) liefern.
  3077. ;
  3078. ;         2) Die MCB-Kette durchlaufen, dabei die Länge in Paragraphen
  3079. ;        aller Blöcke addieren die zu diesem Prozeß gehören.
  3080. ;
  3081. ;         3) EMS prüfen (wenn der method Parameter EMS erlaubt):
  3082. ;        - ist ein EMS Treiber installiert?
  3083. ;        - sind genügend EMS-Seiten verfügbar?
  3084. ;        Wenn dies erfüllt ist, werden die EMS-Seiten alloziert,
  3085. ;        und die Routine liefert einen Erfolgscode (1).
  3086. ;
  3087. ;         4) XMS prüfen (wenn der method Parameter XMS erlaubt):
  3088. ;        - ist ein XMS Treiber installiert?
  3089. ;        - ist ein ausreichend großer XMS-Bereich verfügbar?
  3090. ;        Wenn dies erfüllt ist, wird der XMS-Bereich alloziert,
  3091. ;        und die Routine liefert einen Erfolgscode (2).
  3092. ;
  3093. ;         5) Dateiauslagerung prüfen (wenn der method Parameter es erlaubt):
  3094. ;        - die Datei erzeugen,
  3095. ;        - den benötigten Platz auf Datei prä-allozieren indem
  3096. ;          an das Ende positioniert und ein Byte geschrieben wird.
  3097. ;        Konnte die Datei geschrieben werden, liefert die Routine
  3098. ;        einen Erfolgscode (4).
  3099. ;
  3100. ;         6) Fehlercode liefern (-1).
  3101. ;<
  3102.     IFDEF    PASCAL
  3103.     IFDEF    FARCALL
  3104. prep_swap    PROC    far pmethod: word, swapfname: dword
  3105.     ELSE
  3106. prep_swap    PROC    near pmethod: word, swapfname: dword
  3107.     ENDIF
  3108.     ELSE
  3109. prep_swap    PROC    uses si di,pmethod:word,swapfname:ptr byte
  3110.     ENDIF
  3111.     LOCAL    totparas: word
  3112. ;
  3113.     IFDEF    TC_HUGE
  3114.     mov    ax,SEG my_data
  3115.     mov    ds,ax
  3116.     ENDIF
  3117. ;
  3118.     IFDEF    PASCAL
  3119.     cld
  3120.     mov    ax,prefixseg
  3121.     ELSE
  3122.     IFDEF    TC_HUGE
  3123.     mov    ax,SEG _psp
  3124.     mov    es,ax
  3125.     mov    ax,es:_psp
  3126.     ELSE
  3127.     mov    ax,_psp
  3128.     ENDIF
  3129.     ENDIF
  3130. ;
  3131.     dec    ax
  3132.     mov    swap_prep.psp_mcb,ax
  3133.     mov    swap_prep.first_mcb,ax    ;e init first MCB to PSP
  3134.                     ;d ersten MCB auf PSP initialisieren
  3135. ;
  3136. ;e    Make a copy of the environment pointer in the PSP
  3137. ;d    Eine Kopie vom Umgebungsvariablenblock-Pointer des PSP sichern
  3138. ;
  3139.     inc    ax
  3140.     mov    es,ax
  3141.     mov    bx,es:psp_envptr
  3142.     dec    bx
  3143.     mov    swap_prep.env_mcb,bx
  3144.     mov    swap_prep.noswap_mcb,0
  3145.     test    pmethod,DONT_SWAP_ENV
  3146.     jz    can_swap_env
  3147.     mov    swap_prep.noswap_mcb,bx
  3148. ;
  3149. can_swap_env:
  3150.     IF    NOT NO_INHERIT
  3151.     push    ax
  3152.     mov    swap_prep.noswap_mcb2,0
  3153.     mov    ax,3000h
  3154.     int    21h
  3155.     cmp    al,3
  3156.     jb    no_exthandle
  3157.     ja    check_exthandle
  3158.     cmp    ah,33
  3159.     jb    no_exthandle
  3160. ;
  3161. check_exthandle:
  3162.     mov    ax,es:psp_handleptrs
  3163.     mov    bx,es
  3164.     cmp    ax,bx
  3165.     je    no_exthandle
  3166.     dec    ax
  3167.     mov    swap_prep.noswap_mcb2,ax
  3168. ;
  3169. no_exthandle:
  3170.     pop    ax
  3171.     ENDIF
  3172. ;
  3173. ;e    Check if spawn is too low in memory
  3174. ;d    Prüfen ob dieses Modul zu weit unten im Speicher liegt
  3175. ;
  3176.     mov    bx,cs
  3177.     mov    dx,offset lowcode_begin
  3178.     mov    cl,4
  3179.     shr    dx,cl
  3180.     add    bx,dx            ;e normalized start of this code
  3181.                     ;d Normalisierter Beginn des Codes
  3182.     mov    dx,keep_paras        ;e the end of the modified area
  3183.                     ;d Ende des modifizierten Bereichs
  3184.     add    dx,ax            ;e plus PSP = end paragraph
  3185.                     ;d plus PSP = letzer Paragraph
  3186.     cmp    bx,dx
  3187.     ja    prepswap_ok    ;e ok if start of code > end of low mem
  3188.                 ;d OK wenn Code-Beginn > Ende residenter Teil
  3189.     mov    ax,-2
  3190.     mov    swap_prep.swapmethod,al
  3191.     ret
  3192. ;>e
  3193. ;    Walk the chain of memory blocks, adding up the paragraphs
  3194. ;    in all blocks belonging to this process.
  3195. ;    We try to find the first MCB by getting DOS's "list of lists",
  3196. ;    and fetching the word at offset -2 of the returned address.
  3197. ;    If this fails, we use our PSP as the starting point.
  3198. ;<
  3199. ;>d
  3200. ;    Die Speicherblöcke durchgehen und die Größe aller zu diesem
  3201. ;    Prozeß gehörenden Blöcke zusammenzählen.
  3202. ;    Der Anfang der MCB-Liste wird aus der DOS "list of lists"
  3203. ;    abgeleitet. Das Wort an Offset -2 der gelieferten Adresse
  3204. ;    enthält die erste MCB-Adresse. Falls dies fehlschlägt, wird
  3205. ;    der PSP als Ausgangspunkt benutzt.
  3206. ;<
  3207. prepswap_ok:
  3208.     IFDEF    PASCAL
  3209.     IF    PAS_FREE
  3210.     call    @freepas
  3211.     ENDIF
  3212.     ENDIF
  3213.     xor    bx,bx
  3214.     mov    es,bx
  3215.     mov    ah,52h            ; get list of lists
  3216.     int    21h
  3217.     mov    ax,es
  3218.     or    ax,bx
  3219.     jz    prep_no_first
  3220.     mov    es,es:[bx-2]        ; first MCB
  3221.     cmp    es:id,4dh        ; normal ID?
  3222.     jne    prep_no_first
  3223.     mov    swap_prep.first_mcb,es
  3224. ;
  3225. prep_no_first:
  3226.     mov    es,swap_prep.psp_mcb    ;e ES points to base MCB
  3227.                     ;d ES zeigt auf Basis-Block
  3228.     mov    cx,es            ;e save this value
  3229.                     ;d diesen Wert sichern
  3230.     mov    bx,es:owner        ;e the current process
  3231.                     ;d Der aktuelle Prozeß
  3232.     mov    dx,es:paras        ;e memory size in the base block
  3233.                     ;d Speichergröße des Basisblocks
  3234.     sub    dx,keep_paras        ;e minus resident paragraphs
  3235.                     ;d Abzüglich residente Paragraphen
  3236.     mov    si,0            ;e number of MCBs except base
  3237.                     ;d Zähler für MCBs außer Basis
  3238.     mov    di,swap_prep.noswap_mcb
  3239.     mov    ax,swap_prep.first_mcb
  3240.     mov    swap_prep.first_mcb,0
  3241. ;
  3242. prep_mcb_walk:
  3243.     mov    es,ax
  3244.     cmp    ax,cx            ;e base block?
  3245.                     ;d Basisblock?
  3246.     je    prep_walk_next        ;e then don't count again
  3247.                     ;d dann nicht nochmal zählen
  3248.     cmp    ax,di            ;e Non-swap MCB?
  3249.     je    prep_walk_next        ;e then don't count
  3250.                     ;d dann nicht zählen
  3251.     IF    NOT NO_INHERIT
  3252.     cmp    ax,swap_prep.noswap_mcb2
  3253.     je    prep_walk_next
  3254.     ENDIF
  3255. ;
  3256.     cmp    bx,es:owner        ;e our process?
  3257.                     ;d aktueller Prozeß?
  3258.     jne    prep_walk_next        ;e next if not
  3259.                     ;d nächsten wenn nein
  3260.     inc    si
  3261.     mov    ax,es:paras        ;e else get number of paragraphs
  3262.                     ;d sonst Größe in Paragraphen laden
  3263.     add    ax,2            ; + 1 for descriptor + 1 for MCB
  3264.     add    dx,ax            ;e total number of paras
  3265.                     ;d Gesamtzahl Paragraphen
  3266.     cmp    swap_prep.first_mcb,0
  3267.     jne    prep_walk_next
  3268.     mov    swap_prep.first_mcb,es
  3269. ;
  3270. prep_walk_next:
  3271.     cmp    es:id,4dh        ;e normal block?
  3272.                     ;d normaler Block?
  3273.     jne    prep_mcb_ready        ;e ready if end of chain
  3274.                     ;d Fertig wenn ende der Kette
  3275.     mov    ax,es
  3276.     add    ax,es:paras        ; start + length
  3277.     inc    ax            ; next MCB
  3278.     jmp    prep_mcb_walk
  3279. ;
  3280. prep_mcb_ready:
  3281.     mov    totparas,dx
  3282.     mov    swap_prep.total_mcbs,si
  3283. ;
  3284.     IFDEF    PASCAL
  3285.     IF    PAS_FREE
  3286.     call    @restpas
  3287.     ENDIF
  3288.     ENDIF
  3289. ;
  3290.     test    pmethod,XMS_FIRST
  3291.     jnz    check_xms
  3292. ;
  3293. ;e    Check for EMS swap
  3294. ;d    EMS-auslagerung prüfen
  3295. ;
  3296. check_ems:
  3297.     test    pmethod,USE_EMS
  3298.     jz    prep_no_ems
  3299. ;
  3300.     push    ds
  3301.     mov    al,EMM_INT
  3302.     mov    ah,35h
  3303.     int    21h            ;e get EMM int vector
  3304.                     ;d EMM-Interrupt Vektor laden
  3305.     mov    ax,cs
  3306.     mov    ds,ax
  3307.     mov    si,offset emm_name
  3308.     mov    di,10
  3309.     mov    cx,8
  3310.     repz cmpsb            ;e EMM name present?
  3311.                     ;d ist der EMM-Name vorhanden?
  3312.     pop    ds
  3313.     jnz    prep_no_ems
  3314. ;
  3315.     mov    ah,40h            ;e get EMS status
  3316.                     ;d EMS-Status abfragen
  3317.     int    EMM_INT
  3318.     or    ah,ah            ; EMS ok?
  3319.     jnz    prep_no_ems
  3320. ;
  3321.     mov    ah,46h            ;e get EMS version
  3322.                     ;d EMS-Version abfragen
  3323.     int    EMM_INT
  3324.     or    ah,ah            ; AH must be 0
  3325.     jnz    prep_no_ems
  3326. ;
  3327.     cmp    al,30h            ; >= version 3.0?
  3328.     jb    prep_no_ems
  3329. ;
  3330.     mov    ah,41h            ;e Get page frame address
  3331.                     ;d EMS-Frame-Adresse holen
  3332.     int    EMM_INT
  3333.     or    ah,ah
  3334.     jnz    prep_no_ems
  3335. ;
  3336. ;e    EMS present, try to allocate pages
  3337. ;d    EMS vorhanden, versuche Seiten zu allozieren
  3338. ;
  3339.     mov    swap_prep.ems_pageframe,bx
  3340.     mov    bx,totparas
  3341.     add    bx,ems_paramask
  3342.     mov    cl,ems_shift
  3343.     shr    bx,cl
  3344.     mov    ah,43h            ; allocate handle and pages
  3345.     int    EMM_INT
  3346.     or    ah,ah            ;e success?
  3347.                     ;d erfolgreich?
  3348.     jnz    prep_no_ems
  3349. ;
  3350. ;e    EMS pages allocated, swap to EMS
  3351. ;d    EMS-Seiten alloziert, auslagern auf EMS
  3352. ;
  3353.     mov    swap_prep.handle,dx
  3354.     mov    ax,USE_EMS
  3355.     mov    swap_prep.swapmethod,al
  3356.     ret
  3357. ;
  3358. ;e    No EMS allowed, or EMS not present/full. Try XMS.
  3359. ;d    EMS nicht erlaubt, oder EMS nicht vorhanden/voll. XMS versuchen.
  3360. ;
  3361. prep_no_ems:
  3362.     test    pmethod,XMS_FIRST
  3363.     jnz    check_file        ;e don't try again
  3364.                     ;d nicht nochmal versuchen
  3365. ;
  3366. check_xms:
  3367.     test    pmethod,USE_XMS
  3368.     jz    prep_no_xms
  3369. ;
  3370.     mov    ax,4300h        ;e check if XMM driver present
  3371.                     ;d prüfen ob XMM-Treiber vorhanden
  3372.     int    2fh
  3373.     cmp    al,80h            ;e is XMM installed?
  3374.                     ;d ist XMM installiert?
  3375.     jne    prep_no_xms
  3376.     mov    ax,4310h        ;e get XMM entrypoint
  3377.                     ;d XMM-Einsprungadresse holen
  3378.     int    2fh
  3379.     mov    word ptr swap_prep.xmm,bx    ;e save entry address
  3380.                     ;d Einsprungadresse sichern
  3381.     mov    word ptr swap_prep.xmm+2,es
  3382. ;
  3383.     mov    dx,totparas
  3384.     add    dx,xms_paramask        ;e round to nearest multiple of 1k
  3385.                     ;d Auf volle 1k aufrunden
  3386.     mov    cl,xms_shift
  3387.     shr    dx,cl            ;e convert to k
  3388.                     ;d konvertiern in k
  3389.     mov    ah,9            ;e allocate extended memory block
  3390.                     ;d Extended memory block allozieren
  3391.     call    swap_prep.xmm
  3392.     or    ax,ax
  3393.     jz    prep_no_xms
  3394. ;
  3395. ;e    XMS block allocated, swap to XMS
  3396. ;d    XMS-Block alloziert, Auslagern auf XMS.
  3397. ;
  3398.     mov    swap_prep.handle,dx
  3399.     mov    ax,USE_XMS
  3400.     mov    swap_prep.swapmethod,al
  3401.     ret
  3402. ;
  3403. ;e    No XMS allowed, or XMS not present/full. Try File swap.
  3404. ;d    XMS nicht erlaubt, oder XMS nicht vorhanden/voll. Datei versuchen.
  3405. ;
  3406. prep_no_xms:
  3407.     test    pmethod,XMS_FIRST
  3408.     jz    check_file
  3409.     jmp    check_ems
  3410. ;
  3411. check_file:
  3412.     test    pmethod,USE_FILE
  3413.     jnz    prep_do_file
  3414.     jmp    prep_no_file
  3415. ;
  3416. prep_do_file:
  3417.     push    ds
  3418.     IF    ptrsize
  3419.     lds    dx,swapfname
  3420.     ELSE
  3421.     mov    dx,swapfname
  3422.     ENDIF
  3423.     IFDEF    PASCAL
  3424.     inc    dx            ;e skip length byte
  3425.                     ;d Längenbyte überspringen
  3426.     ENDIF
  3427.     mov    cx,2            ; hidden attribute
  3428.     test    pmethod,HIDE_FILE
  3429.     jnz    prep_hide
  3430.     xor    cx,cx            ; normal attribute
  3431. ;
  3432. prep_hide:
  3433.     mov    ah,3ch            ; create file
  3434.     test    pmethod,CREAT_TEMP
  3435.     jz    prep_no_temp
  3436.     mov    ah,5ah
  3437. ;
  3438. prep_no_temp:
  3439.     int    21h            ; create/create temp
  3440.     jnc    prep_got_file
  3441.     jmp    prep_no_file
  3442. ;
  3443. prep_got_file:
  3444.     mov    bx,ax            ; handle
  3445. ;
  3446. ;e    save the file name
  3447. ;d    Dateinamen sichern
  3448. ;
  3449.     pop    es
  3450.     push    es
  3451.     mov    di,offset swap_prep.swapfilename
  3452.     mov    cx,81
  3453.     mov    si,dx
  3454.     rep movsb
  3455. ;
  3456.     pop    ds
  3457.     mov    swap_prep.handle,bx
  3458. ;
  3459. ;e    preallocate the file
  3460. ;d    Datei-Speicherplatz prä-allozieren
  3461. ;
  3462.     test    pmethod,NO_PREALLOC
  3463.     jnz    prep_noprealloc
  3464.     test    pmethod,CHECK_NET
  3465.     jz    prep_nonetcheck
  3466. ;
  3467. ;e    check whether file is on a network drive, and don't preallocate
  3468. ;e    if so. preallocation can slow down swapping significantly when
  3469. ;e    running on certain networks (Novell)
  3470. ;d    Prüfen ob Datei auf einem Netwerk-Laufwerk liegt, und nicht
  3471. ;d    präallozieren wenn ja. Ein Präallozieren kann den Swap-Vorgang
  3472. ;d    erheblich verlangsamen wenn es auf Novell-Drives ausgeführt wird.
  3473. ;
  3474.     mov    ax,440ah    ; check if handle is remote
  3475.     int    21h
  3476.     jc    prep_nonetcheck    ;e assume not remote if function fails
  3477.                 ;d kein Netz wenn Funktion Fehler liefert
  3478.     test    dh,80h        ;e DX bit 15 set ?
  3479.                 ;d Ist Bit 15 von DX gesetzt?
  3480.     jnz    prep_noprealloc    ;e remote if yes
  3481.                 ;d Netzwerk-Datei wenn ja
  3482. ;
  3483. prep_nonetcheck:
  3484.     mov    dx,totparas
  3485.     mov    cl,4
  3486.     rol    dx,cl
  3487.     mov    cx,dx
  3488.     and    dx,0fff0h
  3489.     and    cx,0000fh
  3490.     sub    dx,1
  3491.     sbb    cx,0
  3492.     mov    si,dx            ; save
  3493.     mov    ax,4200h        ; move file pointer, absolute
  3494.     int    21h
  3495.     jc    prep_file_err
  3496.     cmp    dx,cx
  3497.     jne    prep_file_err
  3498.     cmp    ax,si
  3499.     jne    prep_file_err
  3500.     mov    cx,1            ;e write 1 byte
  3501.                     ;d 1 Byte schreiben
  3502.     mov    ah,40h
  3503.     int    21h
  3504.     jc    prep_file_err
  3505.     cmp    ax,cx
  3506.     jne    prep_file_err
  3507. ;
  3508.     mov    ax,4200h        ; move file pointer, absolute
  3509.     xor    dx,dx
  3510.     xor    cx,cx            ;e rewind to beginning
  3511.                     ;d Auf Anfang zurückpositionieren
  3512.     int    21h
  3513.     jc    prep_file_err
  3514. ;
  3515. prep_noprealloc:
  3516.     mov    ax,USE_FILE
  3517.     mov    swap_prep.swapmethod,al
  3518.     ret
  3519. ;
  3520. prep_file_err:
  3521.     mov    ah,3eh            ; close file
  3522.     int    21h
  3523.     mov    dx,offset swap_prep.swapfilename
  3524.     mov    ah,41h            ; delete file
  3525.     int    21h
  3526. ;
  3527. prep_no_file:
  3528.     mov    ax,-1
  3529.     mov    swap_prep.swapmethod,al
  3530.     ret
  3531. ;
  3532. prep_swap    endp
  3533. ;
  3534.     end
  3535.  
  3536.